diff options
| author | Adam Soltys <[email protected]> | 2026-07-04 19:29:08 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-07-04 19:29:08 -0700 |
| commit | 1d9cac6ca92187718eafbd567562875d25fa772b (patch) | |
| tree | c5ffaa9205d0236fda69ca798d73c33dd9c49a54 /src/features | |
| parent | cc2c05d2a1b7a9601eb3cb0df998483099e590cc (diff) | |
| download | coinosv3-1d9cac6ca92187718eafbd567562875d25fa772b.tar.gz coinosv3-1d9cac6ca92187718eafbd567562875d25fa772b.zip | |
Ark: recover from stale vtxo state
Match captaind's actual 'not spendable' error so a crashed or foreign
spend fails the action instead of retrying forever, and reconcile
locally-spendable vtxos against the server (GetVtxoStatus + ownership
attestation) when an ark address lands in the send form. boardFee now
treats absent proto3 fee fields as zero (Second's signet boards free).
Co-Authored-By: Claude Fable 5 <[email protected]>
Diffstat (limited to 'src/features')
| -rw-r--r-- | src/features/ark.js | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/src/features/ark.js b/src/features/ark.js index 868192a..ca718ee 100644 --- a/src/features/ark.js +++ b/src/features/ark.js @@ -104,6 +104,17 @@ export function arkFeature(ctx) { return ark.balance(); } + // An ark address in the send form signals a send is coming: verify our + // spendable vtxos against the server now, so a stale one (same seed active + // elsewhere, restored state) is dropped before coin selection instead of + // failing at cosign time. Throttled — this fires from the render path. + let arkReconciledAt = 0; + function maybeReconcile() { + if (Date.now() - arkReconciledAt < 30_000) return; + arkReconciledAt = Date.now(); + connectArk().then((mgr) => mgr.reconcile()).catch(() => {}); + } + function arkSendReview() { if (ui.arkSent) { return h( @@ -408,7 +419,9 @@ export function arkFeature(ctx) { isSendDest(a) { return isArkAddress(a) && arkAvailable(); }, hideSendControls(a) { return isArkAddress(a); }, sendFormNote(a) { - return isArkAddress(a) ? h('div', { class: 'small faint' }, t('arkSendHint')) : null; + if (!isArkAddress(a)) return null; + maybeReconcile(); + return h('div', { class: 'small faint' }, t('arkSendHint')); }, interceptReview(s) { if (s.recipients.length === 1 && isArkAddress(s.recipients[0].address)) { |
