aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-24 16:25:22 -0700
committerAdam Soltys <[email protected]>2026-06-24 16:25:22 -0700
commitd3199c42de3652f1e4b81a59b8b0756b9c2c4eb7 (patch)
treeecae9b183909b98d2d32dd6106d5e273b47c06a0
parent31268770ce5d824eb598b51f0fa159d21239ce2b (diff)
downloadcoinosv3-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]>
-rw-r--r--src/app.js32
1 files changed, 20 insertions, 12 deletions
diff --git a/src/app.js b/src/app.js
index d704831..c77ee44 100644
--- a/src/app.js
+++ b/src/app.js
@@ -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(); }
}