Skip to content

Commit a528d6f

Browse files
committed
fixup! Cache and restore wallets
1 parent 11ae3f0 commit a528d6f

4 files changed

Lines changed: 147 additions & 9 deletions

File tree

src/core/cache/cache-wallet-cleaners.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ export const asWalletCacheFile = asObject({
5454
version: asValue(1),
5555
// pluginId -> tokenId -> token
5656
tokens: asObject(asObject(asEdgeToken)),
57+
// pluginId -> tokenId -> token (user-added custom tokens)
58+
customTokens: asOptional(asObject(asObject(asEdgeToken)), {}),
5759
wallets: asArray(asCachedWallet),
5860
// Config otherMethods names per plugin
5961
configOtherMethodNames: asObject(asArray(asString))

src/core/cache/cache-wallet-saver.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,15 @@ export function makeWalletCacheSaver(
116116
}
117117
}
118118

119+
// Save custom tokens per plugin:
120+
const customTokens: WalletCacheFile['customTokens'] = {}
121+
for (const [pluginId, config] of Object.entries(account.currencyConfig)) {
122+
const pluginCustomTokens = config.customTokens
123+
if (Object.keys(pluginCustomTokens).length > 0) {
124+
customTokens[pluginId] = pluginCustomTokens
125+
}
126+
}
127+
119128
// Save config otherMethods names per plugin:
120129
const configOtherMethodNames: WalletCacheFile['configOtherMethodNames'] =
121130
{}
@@ -159,6 +168,7 @@ export function makeWalletCacheSaver(
159168
const cacheFile: WalletCacheFile = asWalletCacheFile({
160169
version: 1,
161170
tokens,
171+
customTokens,
162172
wallets,
163173
configOtherMethodNames
164174
})

src/core/cache/cached-currency-config.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ export function makeCachedCurrencyConfig(
6969
return await fn(await waitForRealConfig())
7070
}
7171

72-
// Build token map from cached data (cached tokens are EdgeTokens)
72+
// Build token maps from cached data (cached tokens are EdgeTokens)
7373
const allTokens: EdgeTokenMap = cacheFile.tokens[pluginId] ?? {}
74+
const customTokens: EdgeTokenMap = cacheFile.customTokens[pluginId] ?? {}
7475

7576
// Get otherMethods names for this plugin
7677
const otherMethodNames = cacheFile.configOtherMethodNames[pluginId] ?? []
@@ -80,15 +81,18 @@ export function makeCachedCurrencyConfig(
8081

8182
currencyInfo,
8283

83-
// Tokens (read-only, can be cached):
84+
// Tokens (delegate to real config when available, fall back to cache):
8485
get allTokens(): EdgeTokenMap {
85-
return allTokens
86+
const realConfig = tryGetRealConfig()
87+
return realConfig != null ? realConfig.allTokens : allTokens
8688
},
8789
get builtinTokens(): EdgeTokenMap {
88-
return allTokens
90+
const realConfig = tryGetRealConfig()
91+
return realConfig != null ? realConfig.builtinTokens : allTokens
8992
},
9093
get customTokens(): EdgeTokenMap {
91-
return {}
94+
const realConfig = tryGetRealConfig()
95+
return realConfig != null ? realConfig.customTokens : customTokens
9296
},
9397

9498
// Token methods (need real config, delegate):
@@ -116,9 +120,10 @@ export function makeCachedCurrencyConfig(
116120
return await delegate(async c => await c.removeCustomToken(tokenId))
117121
},
118122

119-
// Always-enabled tokens (read-only cached, write delegates):
123+
// Always-enabled tokens (delegate when available, write delegates):
120124
get alwaysEnabledTokenIds(): string[] {
121-
return []
125+
const realConfig = tryGetRealConfig()
126+
return realConfig != null ? realConfig.alwaysEnabledTokenIds : []
122127
},
123128

124129
async changeAlwaysEnabledTokenIds(tokenIds: string[]): Promise<void> {
@@ -127,9 +132,10 @@ export function makeCachedCurrencyConfig(
127132
)
128133
},
129134

130-
// User settings (read-only cached, write delegates):
135+
// User settings (delegate when available, write delegates):
131136
get userSettings(): object | undefined {
132-
return {}
137+
const realConfig = tryGetRealConfig()
138+
return realConfig != null ? realConfig.userSettings : {}
133139
},
134140

135141
async changeUserSettings(settings: object): Promise<void> {

test/core/cache/wallet-cache.test.ts

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { expect } from 'chai'
1515
import { describe, it } from 'mocha'
1616

1717
import { walletCacheSaverConfig } from '../../../src/core/cache/cache-wallet-saver'
18+
import { EdgeToken } from '../../../src/index'
1819
import { makeFakeEdgeWorld } from '../../../src/index'
1920
import { snooze } from '../../../src/util/snooze'
2021
import {
@@ -1347,4 +1348,123 @@ describe('wallet cache', function () {
13471348

13481349
await account2.logout()
13491350
})
1351+
1352+
// ===========================================================================
1353+
// Config caching tests
1354+
// ===========================================================================
1355+
1356+
it('caches custom tokens on config', async function () {
1357+
this.timeout(10000)
1358+
1359+
const world = await makeFakeEdgeWorld([fakeUser], quiet)
1360+
const context = await world.makeEdgeContext({
1361+
...contextOptions,
1362+
plugins: { fakecoin: true }
1363+
})
1364+
1365+
// First login - add a custom token
1366+
const account1 = await context.loginWithPIN(fakeUser.username, fakeUser.pin)
1367+
const walletInfo = account1.getFirstWalletInfo('wallet:fakecoin')
1368+
if (walletInfo == null) throw new Error('No wallet')
1369+
1370+
await account1.waitForCurrencyWallet(walletInfo.id)
1371+
1372+
const customToken: EdgeToken = {
1373+
currencyCode: 'CUSTOM',
1374+
displayName: 'Custom Token',
1375+
denominations: [{ multiplier: '1000', name: 'CUSTOM' }],
1376+
networkLocation: {
1377+
contractAddress:
1378+
'0X7CD5885327FD60E825D67D32F9D22B018227A208AA3C4819DA15B36B5D5869D3'
1379+
}
1380+
}
1381+
await account1.currencyConfig.fakecoin.addCustomToken(customToken)
1382+
1383+
const customTokenId =
1384+
'7cd5885327fd60e825d67d32f9d22b018227a208aa3c4819da15b36b5d5869d3'
1385+
expect(account1.currencyConfig.fakecoin.customTokens).to.have.property(
1386+
customTokenId
1387+
)
1388+
1389+
// Wait for cache saver to write (throttled to 50ms in tests):
1390+
await snooze(CACHE_SAVE_WAIT_MS)
1391+
await account1.logout()
1392+
1393+
// Second login - use gate to block engine, verify custom tokens from cache
1394+
const { gate } = createEngineGate()
1395+
fakePluginTestConfig.engineGate = gate
1396+
1397+
const account2 = await context.loginWithPIN(fakeUser.username, fakeUser.pin)
1398+
const cachedConfig = account2.currencyConfig.fakecoin
1399+
1400+
expect(cachedConfig.customTokens).to.have.property(customTokenId)
1401+
expect(cachedConfig.customTokens[customTokenId].currencyCode).equals(
1402+
'CUSTOM'
1403+
)
1404+
1405+
// Custom tokens should also appear in allTokens
1406+
expect(cachedConfig.allTokens).to.have.property(customTokenId)
1407+
1408+
await account2.logout()
1409+
})
1410+
1411+
it('config getters delegate to real config after engine loads', async function () {
1412+
this.timeout(10000)
1413+
1414+
const world = await makeFakeEdgeWorld([fakeUser], quiet)
1415+
const context = await world.makeEdgeContext({
1416+
...contextOptions,
1417+
plugins: { fakecoin: true }
1418+
})
1419+
1420+
// First login - add a custom token to populate the cache
1421+
const account1 = await context.loginWithPIN(fakeUser.username, fakeUser.pin)
1422+
const walletInfo = account1.getFirstWalletInfo('wallet:fakecoin')
1423+
if (walletInfo == null) throw new Error('No wallet')
1424+
1425+
await account1.waitForCurrencyWallet(walletInfo.id)
1426+
1427+
const customToken: EdgeToken = {
1428+
currencyCode: 'CUSTOM',
1429+
displayName: 'Custom Token',
1430+
denominations: [{ multiplier: '1000', name: 'CUSTOM' }],
1431+
networkLocation: {
1432+
contractAddress:
1433+
'0X7CD5885327FD60E825D67D32F9D22B018227A208AA3C4819DA15B36B5D5869D3'
1434+
}
1435+
}
1436+
await account1.currencyConfig.fakecoin.addCustomToken(customToken)
1437+
1438+
// Wait for cache saver to write (throttled to 50ms in tests):
1439+
await snooze(CACHE_SAVE_WAIT_MS)
1440+
await account1.logout()
1441+
1442+
// Second login - gate blocks engine
1443+
const { gate, release } = createEngineGate()
1444+
fakePluginTestConfig.engineGate = gate
1445+
1446+
const account2 = await context.loginWithPIN(fakeUser.username, fakeUser.pin)
1447+
const cachedConfig = account2.currencyConfig.fakecoin
1448+
1449+
// In cache mode: builtinTokens should have cached data
1450+
expect(cachedConfig.builtinTokens).to.have.property('badf00d5')
1451+
1452+
// In cache mode: customTokens should have cached data
1453+
const customTokenId =
1454+
'7cd5885327fd60e825d67d32f9d22b018227a208aa3c4819da15b36b5d5869d3'
1455+
expect(cachedConfig.customTokens).to.have.property(customTokenId)
1456+
1457+
// Release the gate to allow real config to load
1458+
release()
1459+
1460+
// Use a delegating write method to confirm the real config is loaded,
1461+
// then verify getters delegate to the real config:
1462+
await cachedConfig.changeAlwaysEnabledTokenIds(['badf00d5'])
1463+
1464+
expect(cachedConfig.alwaysEnabledTokenIds).deep.equals(['badf00d5'])
1465+
expect(cachedConfig.builtinTokens).to.have.property('badf00d5')
1466+
expect(cachedConfig.customTokens).to.have.property(customTokenId)
1467+
1468+
await account2.logout()
1469+
})
13501470
})

0 commit comments

Comments
 (0)