aboutsummaryrefslogtreecommitdiffstats
path: root/src/app.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-07-04 22:21:12 -0700
committerAdam Soltys <[email protected]>2026-07-04 22:21:12 -0700
commit086bcf33d532f61505a0bc19e8f2d1f08392acce (patch)
treee30d3adeb9adb70029abb7d932ab7bd28a96d010 /src/app.js
parent0f96ea2500a311ab77a9fed3b10ab928370a6b0d (diff)
downloadcoinosv3-086bcf33d532f61505a0bc19e8f2d1f08392acce.tar.gz
coinosv3-086bcf33d532f61505a0bc19e8f2d1f08392acce.zip
Per-network nostr sync + honest balance loading state
One shared d-tag let a network switch apply the mainnet snapshot to a signet wallet (the flash of wrong balance) and clobber mainnet state on the relays. Each network now syncs its own replaceable event (mainnet keeps the legacy bare tag), snapshots carry netName, and a foreign-net snapshot is never applied. The balance card spins until cache, Nostr, or a scan has populated this network once — 'scanning' alone missed the cache/Nostr window after wallet.load(). Co-Authored-By: Claude Fable 5 <[email protected]>
Diffstat (limited to 'src/app.js')
-rw-r--r--src/app.js14
1 files changed, 10 insertions, 4 deletions
diff --git a/src/app.js b/src/app.js
index 2730211..4912ea1 100644
--- a/src/app.js
+++ b/src/app.js
@@ -1877,8 +1877,12 @@ function offlineBanner() {
}
function balanceCard() {
- // Only dim on the very first load; background updates happen silently.
- const firstLoad = wallet.scanning && !wallet.loaded;
+ // Dim + spin until this network has data (cache, Nostr state, or a scan has
+ // populated balances once). `scanning` alone misses the window between
+ // wallet.load() and the first scan — the cache check and Nostr sync on a
+ // network switch — where a bare 0 reads as a final balance. Background
+ // updates after that happen silently.
+ const firstLoad = !wallet.loaded && !wallet.offline;
const pending = wallet.pendingIncoming;
const featLines = featureAll('balanceLines');
return h(
@@ -1888,7 +1892,9 @@ function balanceCard() {
// Headline is the spendable balance: confirmed coins plus our own pending
// change, minus gift locks — so a pending spend debits immediately, while a
// pending incoming receive stays out of it until it confirms.
- h('div', { class: 'amt', style: firstLoad ? 'opacity:.3' : '' }, fmtAmount(wallet.spendable), ' ', unitTag('unit')),
+ h('div', { class: 'amt', style: firstLoad ? 'opacity:.3' : '' },
+ firstLoad ? h('span', { class: 'spinner sm', style: 'margin-right:8px' }) : null,
+ fmtAmount(wallet.spendable), ' ', unitTag('unit')),
pending > 0 || featLines.length
? h(
'div',
@@ -2746,7 +2752,7 @@ function historyTab() {
}
if (wallet.offline)
return h('div', { class: 'card' }, h('p', { class: 'muted center', style: 'margin:0' }, t('historyOffline')));
- if ((wallet.scanning && !wallet.loaded) || (wallet.historyLoading && !txs.length))
+ if (!wallet.loaded || (wallet.historyLoading && !txs.length))
return h(
'div',
{ class: 'card center col', style: 'align-items:center;gap:10px' },