Skip to content

Commit 600301a

Browse files
committed
Add a versioned wallet UI-state cache file and Redux seeding action
Add walletCache.json (name, fiat code, enabled token IDs, last-known balances) with a versioned cleaner, plus a CURRENCY_WALLET_CACHE_LOADED action that seeds the wallet's Redux slice. Cached balances never overwrite live engine data, and the later authoritative file loads replace the cached values exactly as they replace initial state today.
1 parent 6ff64b4 commit 600301a

4 files changed

Lines changed: 76 additions & 4 deletions

File tree

src/core/actions.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
EdgeBalanceMap,
23
EdgeCorePlugin,
34
EdgeCorePluginsInit,
45
EdgeCurrencyTools,
@@ -271,6 +272,18 @@ export type RootAction =
271272
tools: Promise<EdgeCurrencyTools>
272273
}
273274
}
275+
| {
276+
// Called when the wallet's UI-state cache file loads from disk,
277+
// seeding Redux before the engine exists.
278+
type: 'CURRENCY_WALLET_CACHE_LOADED'
279+
payload: {
280+
balanceMap: EdgeBalanceMap
281+
enabledTokenIds: string[]
282+
fiatCurrencyCode: string
283+
name: string | null
284+
walletId: string
285+
}
286+
}
274287
| {
275288
type: 'CURRENCY_WALLET_CHANGED_PAUSED'
276289
payload: {

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,30 @@ export const asPublicKeyFile = asObject({
402402
})
403403
})
404404

405+
/**
406+
* Cached wallet UI state, stored in the wallet's local storage.
407+
* This is everything the GUI needs to render a wallet in the wallet list
408+
* before its engine exists. Balances are last-known values,
409+
* and are explicitly allowed to be stale.
410+
*/
411+
export interface WalletCacheFile {
412+
version: 1
413+
name: string | null
414+
fiatCurrencyCode: string
415+
enabledTokenIds: string[]
416+
417+
/** Integer strings. The `null` tokenId is spelled '' here. */
418+
balances: { [tokenId: string]: string }
419+
}
420+
421+
export const asWalletCacheFile: Cleaner<WalletCacheFile> = asObject({
422+
version: asValue(1),
423+
name: asEither(asString, asNull),
424+
fiatCurrencyCode: asString,
425+
enabledTokenIds: asArray(asString),
426+
balances: asObject(asIntegerString)
427+
})
428+
405429
/**
406430
* The wallet's local storage file for the last seen "checkpoint". The core
407431
* does not know the contents of the checkpoint, so it just as an arbitrary

src/core/currency/wallet/currency-wallet-reducer.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ const currencyWalletInner = buildReducer<
197197
return action.payload.enabledTokenIds
198198
} else if (action.type === 'CURRENCY_WALLET_ENABLED_TOKENS_CHANGED') {
199199
return action.payload.enabledTokenIds
200+
} else if (action.type === 'CURRENCY_WALLET_CACHE_LOADED') {
201+
return action.payload.enabledTokenIds
200202
} else if (action.type === 'CURRENCY_ENGINE_DETECTED_TOKENS') {
201203
const { enablingTokenIds } = action.payload
202204
return uniqueStrings([...state, ...enablingTokenIds])
@@ -282,13 +284,17 @@ const currencyWalletInner = buildReducer<
282284
},
283285

284286
fiat(state = '', action): string {
285-
return action.type === 'CURRENCY_WALLET_FIAT_CHANGED'
287+
return action.type === 'CURRENCY_WALLET_FIAT_CHANGED' ||
288+
action.type === 'CURRENCY_WALLET_CACHE_LOADED'
286289
? action.payload.fiatCurrencyCode
287290
: state
288291
},
289292

290293
fiatLoaded(state = false, action): boolean {
291-
return action.type === 'CURRENCY_WALLET_FIAT_CHANGED' ? true : state
294+
return action.type === 'CURRENCY_WALLET_FIAT_CHANGED' ||
295+
action.type === 'CURRENCY_WALLET_CACHE_LOADED'
296+
? true
297+
: state
292298
},
293299

294300
files(state = {}, action): TxFileJsons {
@@ -352,6 +358,14 @@ const currencyWalletInner = buildReducer<
352358
out.set(tokenId, balance)
353359
return out
354360
}
361+
if (action.type === 'CURRENCY_WALLET_CACHE_LOADED') {
362+
// Seed cached balances, but never overwrite live engine data:
363+
const out = new Map(state)
364+
for (const [tokenId, balance] of action.payload.balanceMap) {
365+
if (!out.has(tokenId)) out.set(tokenId, balance)
366+
}
367+
return out
368+
}
355369
return state
356370
},
357371

@@ -379,13 +393,17 @@ const currencyWalletInner = buildReducer<
379393
},
380394

381395
name(state = null, action): string | null {
382-
return action.type === 'CURRENCY_WALLET_NAME_CHANGED'
396+
return action.type === 'CURRENCY_WALLET_NAME_CHANGED' ||
397+
action.type === 'CURRENCY_WALLET_CACHE_LOADED'
383398
? action.payload.name
384399
: state
385400
},
386401

387402
nameLoaded(state = false, action): boolean {
388-
return action.type === 'CURRENCY_WALLET_NAME_CHANGED' ? true : state
403+
return action.type === 'CURRENCY_WALLET_NAME_CHANGED' ||
404+
action.type === 'CURRENCY_WALLET_CACHE_LOADED'
405+
? true
406+
: state
389407
},
390408

391409
seenTxCheckpoint(state = null, action) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { makeJsonFile } from '../../../util/file-helpers'
2+
import { asWalletCacheFile } from './currency-wallet-cleaners'
3+
4+
/**
5+
* Cached wallet UI state, stored on the wallet's local disklet
6+
* alongside `publicKey.json`. See `asWalletCacheFile` for the schema.
7+
*/
8+
export const WALLET_CACHE_FILE = 'walletCache.json'
9+
export const walletCacheFile = makeJsonFile(asWalletCacheFile)
10+
11+
/**
12+
* Tuning for the wallet UI-state cache saver.
13+
* Tests override the throttle to run quickly.
14+
*/
15+
export const walletCacheSaverConfig = {
16+
throttleMs: 5000
17+
}

0 commit comments

Comments
 (0)