aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.js18
-rw-r--r--src/i18n.js2
-rw-r--r--src/wallet.js9
3 files changed, 19 insertions, 10 deletions
diff --git a/src/app.js b/src/app.js
index daf9782..727e3cc 100644
--- a/src/app.js
+++ b/src/app.js
@@ -2254,18 +2254,22 @@ function silentPaymentReceiveCard(spAddr) {
h('div', { style: 'align-self:center' }, h('div', { html: qrSvg(spAddr) })),
h('div', { class: 'addr-box break', style: 'width:100%;font-size:12px' }, spAddr),
copyBtn(spAddr, t('copyAddress')),
- bal.count
- ? h('div', { class: 'small', style: 'text-align:center' },
- t('spReceived', { amount: fmtAmount(bal.confirmed + bal.pending) + ' ' + unitLabel(), n: bal.count }))
- : null,
- h('button', { class: 'btn-block', disabled: wallet.spScanning, onClick: doSpScan },
- wallet.spScanning ? t('spScanning') : t('spScan'))
+ h('div', { class: 'row between', style: 'align-items:center' },
+ h('span', { class: 'small muted' },
+ wallet.spScanning
+ ? t('spScanning')
+ : bal.count
+ ? t('spReceived', { amount: fmtAmount(bal.confirmed + bal.pending) + ' ' + unitLabel(), n: bal.count })
+ : t('spWatching')),
+ h('button', { class: 'linklike small', disabled: wallet.spScanning, onClick: doSpScan }, t('spRescan'))
+ )
);
}
+// Auto-scanning runs on the poll loop; this is a manual full rescan.
function doSpScan() {
if (wallet.spScanning || wallet.offline) return;
- wallet.scanSilentPayments().catch(() => {}).finally(render);
+ wallet.scanSilentPayments({ rescan: true }).catch(() => {}).finally(render);
render();
}
diff --git a/src/i18n.js b/src/i18n.js
index 5f029a3..f6a94c0 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -305,6 +305,8 @@ const STR = {
spReceiveDesc: 'A reusable address that leaks nothing on-chain — each sender derives a unique, unlinkable output. Scanning finds payments on-device using the indexer set under Data source.',
spScan: 'Scan for silent payments',
spScanning: 'Scanning…',
+ spWatching: 'Watching for payments',
+ spRescan: 'Rescan',
spReceived: 'Found {n} silent payment output(s): {amount}',
spIndexerTitle: 'Silent payment indexer',
spIndexerDesc: 'Where to scan for received silent payments. It only serves public tweak data — your scan key stays on-device — but a public one can see which blocks hold your outputs, so self-host for full privacy.',
diff --git a/src/wallet.js b/src/wallet.js
index 107076a..bff8910 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -307,13 +307,13 @@ export class Wallet {
// Scan the configured SP indexer from the last-scanned height to the tip, find
// outputs paying our scan/spend keys, and verify each is unspent via the chain
// backend (the indexer only does discovery). Updates this.spUtxos.
- async scanSilentPayments({ rescan = false } = {}) {
+ async scanSilentPayments({ rescan = false, silent = false } = {}) {
const keys = this.silentPaymentKeys();
const indexer = spIndexerUrl(this.netName);
if (!keys || !indexer || this.offline) return { unavailable: true };
if (this.spScanning) return { busy: true };
this.spScanning = true;
- this.emit();
+ if (!silent) this.emit(); // manual scans show a "Scanning…" state; auto-scans stay quiet
try {
if (rescan) { this.spUtxos = []; this.lastSpScan = 0; }
const from = (this.lastSpScan || 0) + 1;
@@ -345,12 +345,13 @@ export class Wallet {
} catch {}
}
await this._refreshSpUtxos();
+ this._recomputeBalanceFromChains(); // fold found SP value into the displayed balance
this.saveCache();
this.emit();
return { found: found.length, scanned: tip };
} finally {
this.spScanning = false;
- this.emit();
+ if (!silent) this.emit();
}
}
@@ -729,6 +730,7 @@ export class Wallet {
}
this.loaded = true;
this.saveCache();
+ this.scanSilentPayments({ silent: true }).catch(() => {}); // fold in any silent-payment receipts
} finally {
this._refreshing = false;
this.historyLoading = false; // clear even if an earlier step threw
@@ -1633,6 +1635,7 @@ export class Wallet {
if (Date.now() - (this._lastPoll || 0) < due) return;
this._lastPoll = Date.now();
this.refreshLive();
+ this.scanSilentPayments({ silent: true }).catch(() => {}); // pick up new SP receipts (incremental, cheap)
}, 1000);
// No periodic full re-scan: the WS (and the frontier poll above) keep the
// balance current, and refreshLive's _reconcileHeld catches spends of held