diff options
| author | Adam Soltys <[email protected]> | 2026-09-10 22:14:36 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-09-10 22:14:36 -0700 |
| commit | b19cf9672532a8f6c347dc8fe99d83492bd478fd (patch) | |
| tree | 740562a31a934415ba3c249b77e3eb1f23b0c05b /src/app.js | |
| parent | f0a5e0de3e68eee184b25ced2393329aec169f6d (diff) | |
| download | coinosv3-b19cf9672532a8f6c347dc8fe99d83492bd478fd.tar.gz coinosv3-b19cf9672532a8f6c347dc8fe99d83492bd478fd.zip | |
The wallet waits for its own state before painting, so nothing jumps.
The Spending balance and its history are read from the ark store, which is
IndexedDB: synchronous to read, asynchronous to OPEN. Boot didn't wait for
it, so every refresh painted a Spending wallet with nothing in it — no
balance, no history — and filled it in a beat later. On a phone that second
paint arrived as a change rather than an arrival: the balance counted itself
up from 0 in green, wearing the animation a received payment gets.
Boot now waits for the store (capped at 800ms — a store that won't open must
not hold the app hostage), and the shell stays up a moment longer instead of
a wrong balance going up. If the store does land past the cap, initArk
retries on it — so a Spending wallet whose state arrived late also connects,
which it previously didn't until something else happened to kick it — and
that catch-up paint forgets the last amounts first, so it reads as state
arriving rather than money.
Also: the zap tally chip loses its underline. In chat the chip is a reaction
chip too, and .chat-react.on still rings it; on a post row the underline just
read as an artifact.
tools/boot-balance-test.js pins the ordering, with IndexedDB slowed so it
can't pass by luck.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
Diffstat (limited to 'src/app.js')
| -rw-r--r-- | src/app.js | 14 |
1 files changed, 14 insertions, 0 deletions
@@ -4914,6 +4914,11 @@ async function importSnapshotFile(e) { const ctx = { h, ui, render, wallet, toast, copy, copyBtn, pasteBtn, blankSend, goBack, goHome, openExternal, fmtAmount, unitLabel, unitTag, parseAmount, getUnit: () => unit, toggleUnit, download, + // "The next balance isn't a change, it's the first real value" — state + // arriving late (the ark store opening past boot's patience) must not read + // as money landing: without this the balance counts up from 0 in green, + // which is the celebration a received payment gets. + forgetAmountAnim: () => _amtLast.clear(), // the one-tap zap amount, synced across devices with the rest of the state zapDefaultSat: () => (wallet.loadFeatureState ? (wallet.loadFeatureState('prefs', {}).zapSat || 0) : 0), setZapDefaultSat: (n) => { @@ -5161,6 +5166,15 @@ loadLocale(getLang()).finally(async () => { // the URL, or the claim would fall through to a normal boot and be lost. if (/^\/(g|ag|lg)\//.test(location.pathname)) await _deferredReady; if (featureHook('bootUrl')) return; // a feature consumed the URL (e.g. a gift claim) + // The Spending balance and its history are read from an IndexedDB-backed + // store, which is synchronous to read but asynchronous to OPEN. Opening a + // wallet before it lands paints a Spending card with nothing in it, and the + // real numbers arrive a beat later — a visible jump, and the balance + // counted itself up in green as if money had just come in. The shell is on + // screen either way; waiting shows it a moment longer rather than showing a + // wrong balance. The hook caps its own wait. + const storeReady = featureHook('arkStoreReady'); + if (storeReady) await storeReady; if (!restoreAccountsState()) render(); }); |
