diff options
| author | Adam Soltys <[email protected]> | 2026-06-24 16:25:22 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-06-24 16:25:22 -0700 |
| commit | d3199c42de3652f1e4b81a59b8b0756b9c2c4eb7 (patch) | |
| tree | ecae9b183909b98d2d32dd6106d5e273b47c06a0 /src | |
| parent | 31268770ce5d824eb598b51f0fa159d21239ce2b (diff) | |
| download | coinosv3-d3199c42de3652f1e4b81a59b8b0756b9c2c4eb7.tar.gz coinosv3-d3199c42de3652f1e4b81a59b8b0756b9c2c4eb7.zip | |
Don't celebrate pre-existing payments on opening a wallet
The "payment received" screen is for payments that arrive while you're
using the wallet, but the seen-index is persisted per-seed, so
re-importing/unlocking/switching to a wallet used before would resurface
the celebration for a payment that had already arrived (and confirmed)
in between. Opening a wallet (import, unlock, account switch, watch-only
add, fresh-session restore) now baselines the ack to the current receive
frontier; only a same-session refresh keeps the persisted ack so an
unacknowledged live celebration survives the refresh.
Verified: with a stale persisted ack, a fresh import shows no
celebration and re-baselines to the current frontier.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/app.js | 32 |
1 files changed, 20 insertions, 12 deletions
@@ -305,7 +305,7 @@ function addWatchOnly() { ui.watchXpub = ''; ui.watchLabel = ''; ui.fromWallet = false; - activateAccount(acc); + activateAccount(acc, { fresh: true }); } // ================================================================ HOW IT WORKS @@ -553,7 +553,7 @@ async function enterWallet(mnemonic, passphrase, opts = {}) { mnemonic: (mnemonic || '').trim().replace(/\s+/g, ' '), passphrase: passphrase || '', }); - await activateAccount(acc, opts); + await activateAccount(acc, { ...opts, fresh: true }); } // Load an account into the wallet and start scanning. Full-account seeds are @@ -597,13 +597,21 @@ async function activateAccount(acc, opts = {}) { // show instantly; a partial frontier-only refresh leaves the state stale and // would let the celebration baseline before a known payment is even counted. await wallet.scan({ silent: hadCache || hadNostr }); - // Persisted acknowledgement: first time, baseline to the current index so we - // don't celebrate historical payments. After that, any advance beyond the - // acknowledged index shows the celebration (and survives refreshes). - let ack = wallet.getReceiveAck(); - if (ack == null) { + // Celebration baseline. Opening/importing/switching a wallet (opts.fresh) + // baselines to the current frontier, so payments already received before + // opening never trigger the "payment received" screen. A same-session + // refresh keeps the persisted ack, so an unacknowledged celebration + // survives the refresh. + let ack; + if (opts.fresh) { ack = wallet.nextReceiveIndex; wallet.setReceiveAck(ack); + } else { + ack = wallet.getReceiveAck(); + if (ack == null) { + ack = wallet.nextReceiveIndex; + wallet.setReceiveAck(ack); + } } ui.receiveSeenIndex = ack; wallet.startRealtime(); @@ -670,7 +678,7 @@ function removeAccount(id) { if (acc.type === 'watch') saveWatchAccounts(); persistAccounts(); if (activeId === id) { - if (accounts.length) activateAccount(accounts[0]); + if (accounts.length) activateAccount(accounts[0], { fresh: true }); else lock(); } else { render(); @@ -679,7 +687,7 @@ function removeAccount(id) { function switchAccount(id) { const acc = accounts.find((a) => a.id === id); - if (acc) activateAccount(acc); + if (acc) activateAccount(acc, { fresh: true }); } // Restore accounts after a refresh (sessionStorage); on a fresh session, prompt @@ -698,7 +706,7 @@ function restoreAccountsState() { const watch = loadWatchAccounts(); if (watch.length) { accounts = watch.slice(); - activateAccount(accounts[0]); + activateAccount(accounts[0], { fresh: true }); return true; } return false; @@ -782,13 +790,13 @@ function unlockVault() { .concat(loadWatchAccounts()); ui.vaultPw = ''; ui.vaultError = ''; - activateAccount(accounts[0]); + activateAccount(accounts[0], { fresh: true }); } function skipVault() { ui.vaultPw = ''; ui.vaultError = ''; const watch = loadWatchAccounts(); - if (watch.length) { accounts = watch.slice(); activateAccount(accounts[0]); } + if (watch.length) { accounts = watch.slice(); activateAccount(accounts[0], { fresh: true }); } else { ui.screen = 'unlock'; render(); } } |
