Cache and restore wallets#703
Conversation
8b8cd1a to
53a3312
Compare
This comment has been minimized.
This comment has been minimized.
53a3312 to
520c5ad
Compare
This comment has been minimized.
This comment has been minimized.
520c5ad to
2bfc435
Compare
This comment has been minimized.
This comment has been minimized.
db35d1c to
38a0e8c
Compare
This comment has been minimized.
This comment has been minimized.
38a0e8c to
45f5446
Compare
This comment has been minimized.
This comment has been minimized.
294dc9f to
e82fdcd
Compare
This comment has been minimized.
This comment has been minimized.
36fa958 to
ac72065
Compare
This comment has been minimized.
This comment has been minimized.
|
Bugbot Autofix prepared fixes for 2 of the 2 bugs found in the latest run.
Or push these changes by commenting: Preview (e6e1588d29)diff --git a/src/core/cache/cached-currency-config.ts b/src/core/cache/cached-currency-config.ts
--- a/src/core/cache/cached-currency-config.ts
+++ b/src/core/cache/cached-currency-config.ts
@@ -141,7 +141,7 @@
// User settings (delegate when available, write delegates):
get userSettings(): object | undefined {
const realConfig = tryGetRealConfig()
- return realConfig != null ? realConfig.userSettings : {}
+ return realConfig != null ? realConfig.userSettings : undefined
},
async changeUserSettings(settings: object): Promise<void> {
diff --git a/src/core/cache/cached-currency-wallet.ts b/src/core/cache/cached-currency-wallet.ts
--- a/src/core/cache/cached-currency-wallet.ts
+++ b/src/core/cache/cached-currency-wallet.ts
@@ -155,7 +155,8 @@
} = cacheData
const shortId = walletId.slice(0, WALLET_ID_DISPLAY_LENGTH)
- const createdDate = new Date(createdString)
+ const parsedDate = new Date(createdString)
+ const createdDate = isNaN(parsedDate.getTime()) ? undefined : parsedDate
// Track mutable state locally. When the GUI calls a setter, we update
// the local value immediately and call update(wallet) to push it |
|
/rebase |
1e3aa7d to
3e6460c
Compare
| result[walletId] = wallet | ||
| } | ||
| } | ||
| return result |
There was a problem hiding this comment.
Because YAOB diffs objects shallowly (===), this needs to be referrentially stable. So you need to store the object somewhere and replace it each time something inside changes. Otherwise we'll either get superfluous updates or missing updates (either would be bad).
3e6460c to
049daf9
Compare
Add missing return in fake plugin getBalance for token balance. Improve @ts-expect-error comment and log swap quote close errors. Co-authored-by: Cursor <cursoragent@cursor.com>
Improve login performance by caching wallet state on a per account level in unencrypted JSON file and rehydrate before wallets load.
049daf9 to
73669de
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: waitForAllWallets ends too early
- Updated waitForAllWallets to wait for pixie-backed real wallets rather than cached stubs and added a passing cache-first regression test.
Or push these changes by commenting:
@cursor push 92a98b7caf
Preview (92a98b7caf)
diff --git a/src/core/account/account-api.ts b/src/core/account/account-api.ts
--- a/src/core/account/account-api.ts
+++ b/src/core/account/account-api.ts
@@ -800,10 +800,11 @@
async waitForAllWallets(): Promise<void> {
return await new Promise((resolve, reject) => {
const check = (): void => {
+ const pixieWallets =
+ ai.props.output.accounts[accountId]?.currencyWallets ?? {}
const busyWallet = this.activeWalletIds.find(
id =>
- this.currencyWallets[id] == null &&
- this.currencyWalletErrors[id] == null
+ pixieWallets[id] == null && this.currencyWalletErrors[id] == null
)
if (busyWallet == null) {
for (const cleanup of cleanups) cleanup()
diff --git a/test/core/cache/wallet-cache.test.ts b/test/core/cache/wallet-cache.test.ts
--- a/test/core/cache/wallet-cache.test.ts
+++ b/test/core/cache/wallet-cache.test.ts
@@ -134,6 +134,52 @@
await account2.logout()
})
+ it('waitForAllWallets waits for real engines', async function () {
+ this.timeout(10000)
+
+ const world = await makeFakeEdgeWorld([fakeUser], quiet)
+ const context = await world.makeEdgeContext({
+ ...contextOptions,
+ plugins: { fakecoin: true }
+ })
+
+ // First login - populate cache
+ const account1 = await context.loginWithPIN(fakeUser.username, fakeUser.pin)
+ const walletInfo = account1.getFirstWalletInfo('wallet:fakecoin')
+ if (walletInfo == null) throw new Error('No wallet')
+
+ await account1.waitForCurrencyWallet(walletInfo.id)
+ await account1.currencyConfig.fakecoin.changeUserSettings({ balance: 9999 })
+
+ // Wait for cache saver to write (throttled to 50ms in tests):
+ await snooze(CACHE_SAVE_WAIT_MS)
+ await account1.logout()
+
+ // Second login - use gate to block engine
+ const { gate, release } = createEngineGate()
+ fakePluginTestConfig.engineGate = gate
+
+ const account2 = await context.loginWithPIN(fakeUser.username, fakeUser.pin)
+ expect(account2.currencyWallets[walletInfo.id]).not.equals(undefined)
+
+ let completed = false
+ const waitPromise = account2.waitForAllWallets().then(() => {
+ completed = true
+ })
+
+ await snooze(BRIDGE_SETTLE_MS)
+ const completedBeforeRelease = completed
+ release()
+ await waitPromise
+
+ expect(completedBeforeRelease).equals(
+ false,
+ 'waitForAllWallets should wait for real engines'
+ )
+
+ await account2.logout()
+ })
+
it('delegates to real wallet after engine loads', async function () {
this.timeout(10000)You can send follow-ups to the cloud agent here.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 73669de. Configure here.
| : undefined, | ||
|
|
||
| // Added for backward compatibility for plugins using core 1.x | ||
| // @ts-expect-error |
There was a problem hiding this comment.
waitForAllWallets ends too early
Medium Severity
After a cache-first login, waitForAllWallets treats cached stub wallets as loaded because currencyWallets merges cache entries and activeWalletIds can come from the cache before keys load. It resolves before real currency engines exist, unlike the pre-change behavior tied to pixie-backed wallets only.
Reviewed by Cursor Bugbot for commit 73669de. Configure here.



Improve login performance by caching wallet state on a per account level in unencrypted JSON file and rehydrate before wallets load.
CHANGELOG
Does this branch warrant an entry to the CHANGELOG?
Dependencies
noneDescription
noneNote
High Risk
Changes the core login and
EdgeAccountwallet surface with delegating proxies and background load; stale cache or yaob/delegation bugs could affect wallet lifecycle, balances shown at login, or disk writes after logout.Overview
Adds per-account wallet caching so login can show wallets before currency engines finish loading. State is written to
accountCache/<storageWalletId>/walletCache.json(unencrypted JSON with balances, tokens, public wallet info—no private keys) and validated with new cleaners.Login path: The account pixie loads the cache after storage wallets init; on success it builds cached
EdgeCurrencyWallet/ config proxies and callsmakeAccountApiwithcacheSetupwhileloadAllFilesruns in the background. Missing or invalid cache keeps the existing synchronous flow.Proxies: Cached wallets implement the full wallet API—getters use disk data until real wallets exist; async calls and disklets delegate via a shared poller (
makeRealObjectPoller). Setters that the GUI reads (paused,name,fiatCurrencyCode,enabledTokenIds) callupdate(wallet)for yaob. A throttledcacheSaversub-pixie persists changes afterkeysLoaded.Account API:
activeWalletIdsandcurrencyWalletsmerge cache with pixie output until every active wallet has a real engine.Also adds
docs/wallet-cache.md, extensive fake-plugin/engine-gate tests, exportsasEdgeToken, and minor swap-close logging plus a fake-plugin token balance return fix.Reviewed by Cursor Bugbot for commit 73669de. Bugbot is set up for automated code reviews on this repo. Configure here.