diff options
| author | Adam Soltys <[email protected]> | 2026-06-24 23:44:48 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-06-24 23:44:48 -0700 |
| commit | faceb2eef8abe14302b057d835f0449bcd06bc59 (patch) | |
| tree | d82769103a809a23d600da2f9f0f9d41bb9332e1 /src/app.js | |
| parent | 6d8df4d5b004ea9a84057ff78b9276262cb8f264 (diff) | |
| download | coinosv3-faceb2eef8abe14302b057d835f0449bcd06bc59.tar.gz coinosv3-faceb2eef8abe14302b057d835f0449bcd06bc59.zip | |
Watch pending-coin addresses; let per-address rescans queue
- watchedAddresses() now includes any address holding an unconfirmed coin (not
just the frontier), so a pending deposit's confirmation pushes over the socket
instantly. Capped at the socket's 10-address limit. refreshLive/rescanAddress
retrack when a new pending coin changes the set.
- While any coin is pending, the frontier poll runs every ~6s even when live, so
confirmations show fast as a belt-and-suspenders to the WS push.
- Per-address rescans no longer disable each other: clicking many queues them,
and the api.js global scheduler (1 concurrent, 500ms spacing, 429 backoff)
serializes and staggers the underlying requests within the rate limit.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Diffstat (limited to 'src/app.js')
| -rw-r--r-- | src/app.js | 17 |
1 files changed, 10 insertions, 7 deletions
@@ -66,7 +66,7 @@ const ui = { giftsPage: 0, // History: current page within the all-gifts list addrScan: false, // Settings: showing the per-address rescan list addrScanPage: 0, // Settings: current page within the address list - rescanningAddr: null, // 'chain/index' of the address currently rescanning + rescanning: new Set(), // 'chain/index' ids queued/in-flight for rescan send: blankSend(), draft: null, // built tx summary awaiting review broadcastTx: null, // scanned signed tx awaiting broadcast confirmation @@ -915,18 +915,21 @@ function brandHeader(withLock) { // The phrase is gated: the real words are never put in the DOM until "Reveal", // so the warning is read first. // Rescan a single address on demand — recovers a deposit to a reused old -// address without a full wallet rescan. +// address without a full wallet rescan. Multiple can be queued at once; the +// API layer's global scheduler serializes and spaces the underlying requests +// (and backs off on 429), so a flurry of clicks stays within the rate limit. async function doRescanAddress(chain, index) { if (wallet.offline) { toast(t('scanOffline')); return; } - ui.rescanningAddr = chain + '/' + index; + const id = chain + '/' + index; + if (ui.rescanning.has(id)) return; // already queued + ui.rescanning.add(id); render(); try { await wallet.rescanAddress(chain, index); - toast(t('rescanDone')); } catch (e) { toast(e.message || t('rescanFailed')); } - ui.rescanningAddr = null; + ui.rescanning.delete(id); render(); } @@ -948,7 +951,7 @@ function addressScanView() { h('div', { class: 'list' }, ...slice.map((a) => { const id = a.chain + '/' + a.index; - const busy = ui.rescanningAddr === id; + const busy = ui.rescanning.has(id); return h('div', { class: 'item' }, h('div', { class: 'grow' }, h('div', { class: 'mono small break' }, shortAddr(a.address, 16, 10), @@ -957,7 +960,7 @@ function addressScanView() { ), busy ? h('button', { class: 'btn-sm', disabled: true }, h('span', { class: 'spinner sm' })) - : h('button', { class: 'btn-sm', disabled: !!ui.rescanningAddr, onClick: () => doRescanAddress(a.chain, a.index) }, t('rescanOne')) + : h('button', { class: 'btn-sm', onClick: () => doRescanAddress(a.chain, a.index) }, t('rescanOne')) ); }) ), |
