aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-25 00:02:51 -0700
committerAdam Soltys <[email protected]>2026-06-25 00:02:51 -0700
commit26a5d52cd11adb22cd3cd3de4ead1b1f3fff38e6 (patch)
tree2f442542d1c39382e785c69e0784b434a7ac8f11
parentd4db7d545d51cde2f5a98426c1839e0fe0745efa (diff)
downloadcoinosv3-26a5d52cd11adb22cd3cd3de4ead1b1f3fff38e6.tar.gz
coinosv3-26a5d52cd11adb22cd3cd3de4ead1b1f3fff38e6.zip
Stop full-scanning the API on every load; go Live before Nostr
The refresh request storm (and the 429s) was a full API re-scan running on every load even when the local cache or Nostr already held the complete state. Now the full scan runs ONLY when there's neither cache nor Nostr (a seed on a fresh device); otherwise the socket + frontier poll keep things current and reconcile held coins — a handful of requests instead of re-querying every historical address plus its utxos and txs. Also reordered: startRealtime() now runs BEFORE syncFromNostr (which blocks up to 6s waiting on the relay) and before any discovery scan, so the wallet goes Live immediately instead of sitting in Polling. retrack() after sync/scan re-subscribes to the final frontier; a fresh open re-baselines its celebration against it. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
-rw-r--r--src/app.js26
1 files changed, 17 insertions, 9 deletions
diff --git a/src/app.js b/src/app.js
index ed4ca8c..53e118e 100644
--- a/src/app.js
+++ b/src/app.js
@@ -617,15 +617,6 @@ async function activateAccount(acc, opts = {}) {
return;
}
try {
- // Cross-device state: pull the latest from Nostr (may supply state on a
- // device with no local cache, or a newer copy from another device). Skipped
- // for watch-only accounts, which have no seed-derived sync key.
- const hadNostr = wallet.watchOnly ? false : await wallet.syncFromNostr();
- // Always do a full scan to fully reconcile (balance, history confirmations,
- // spends, stale cache/relay state). Cache/Nostr just gave us something to
- // 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 });
// 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
@@ -643,7 +634,24 @@ async function activateAccount(acc, opts = {}) {
}
}
ui.receiveSeenIndex = ack;
+
+ // Go Live immediately: the socket must not wait on Nostr (up to 6s) or any
+ // discovery scan. The cache/Nostr state is already on screen.
wallet.startRealtime();
+
+ // Cross-device state in the background. State comes from the local cache or
+ // Nostr — both restore the full balance, coins, and history — so a full API
+ // scan runs ONLY when we have neither (e.g. a seed imported on a fresh device
+ // with no synced state); that's what discovers the used addresses. Otherwise
+ // the socket + frontier poll keep us current with no refresh-time burst.
+ const hadNostr = wallet.watchOnly ? false : await wallet.syncFromNostr();
+ if (!hadCache && !hadNostr) {
+ await wallet.scan({ silent: false });
+ }
+ // Re-baseline a fresh open against the final frontier (Nostr or the discovery
+ // scan may have advanced it) so payments that predate the open don't celebrate.
+ if (opts.fresh) { ack = wallet.nextReceiveIndex; wallet.setReceiveAck(ack); ui.receiveSeenIndex = ack; }
+ wallet.retrack(); // re-subscribe to the latest frontier (Nostr/scan may have moved it)
} catch {
enterOfflineFallback();
}