diff options
| author | Adam Soltys <[email protected]> | 2026-07-04 08:12:38 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-07-04 08:12:38 -0700 |
| commit | 1a8373c36706303802fde5148b74ab1634f0048e (patch) | |
| tree | 8438ba2b8037f1f0b5b3a8ec63adbb54a800c299 /src | |
| parent | cbbf90ed86c29f2c7c61b216be5e51946adaef52 (diff) | |
| download | coinosv3-1a8373c36706303802fde5148b74ab1634f0048e.tar.gz coinosv3-1a8373c36706303802fde5148b74ab1634f0048e.zip | |
Gift claim: name the real failure when the funding tx isn't visible
Claiming a gift whose funding tx is unknown to the claimer's data
source (different network/chain, or not yet propagated) used to fail
with the misleading "already been claimed". Now:
- the claim screen probes the funding tx up front (esplora's status/
outspend endpoints don't 404 for unknown txids, so outspend alone
can't detect this) and shows a network/data-source notice, and
- a missing-inputs broadcast rejection maps to the same explanation
instead of the generic already-claimed message.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QFAcD4V284DvYZZHP7Rxxy
Diffstat (limited to 'src')
| -rw-r--r-- | src/app.js | 15 | ||||
| -rw-r--r-- | src/i18n.js | 1 |
2 files changed, 15 insertions, 1 deletions
@@ -869,6 +869,7 @@ async function activateAccount(acc, opts = {}) { ui.claimCode = opts.gift || null; ui.claimError = ''; ui.claimTaken = null; + ui.claimNotVisible = false; ui.claimChecking = !!opts.gift; // gate the Claim button until we've checked // Restore the tab / open tx from the last session so a refresh keeps the // user's place. A gift link always opens the claim screen instead. @@ -2210,6 +2211,13 @@ async function checkGiftClaimed(code) { try { const res = await wallet.api.outspend(ops[0].txid, ops[0].vout); if (res && res.spent) ui.claimTaken = { txid: res.txid || null }; + // Unknown txids don't 404 on the status/outspend endpoints, so verify the + // funding tx is actually visible — if not, the claimer is likely on a + // different network/data source than the sender (or it hasn't propagated). + if (!ui.claimTaken) { + const tx = await wallet.api.getTx(ops[0].txid).catch(() => null); + ui.claimNotVisible = !tx; + } } catch { // Couldn't check (offline/transient) — leave it claimable; the broadcast in // doClaim is the final guard (a double-spend is rejected by the network). @@ -2251,7 +2259,11 @@ async function doClaim() { if (res && res.spent) ui.claimTaken = { txid: res.txid || null }; } catch {} } - if (!ui.claimTaken) ui.claimError = t('claimFailed'); + if (!ui.claimTaken) { + ui.claimError = /missing.?inputs|missingorspent|bad-txns-inputs/i.test(String(e && e.message)) + ? t('claimNotVisibleBody') // funding tx unknown here: wrong chain/source + : t('claimFailed'); + } } ui.busy = false; render(); @@ -2443,6 +2455,7 @@ function claimScreen() { return acc && !acc.provisional ? t('claimBodyExisting', { name: acc.label }) : t('claimBody'); })()) ), ui.claimError && h('div', { class: 'notice err' }, ui.claimError), + !ui.claimError && ui.claimNotVisible && h('div', { class: 'notice info' }, t('claimNotVisibleBody')), ui.busy || ui.claimChecking ? h('button', { class: 'btn-primary btn-block', disabled: true }, h('span', { class: 'spinner' })) : h('button', { class: 'btn-primary btn-block', onClick: doClaim }, diff --git a/src/i18n.js b/src/i18n.js index 83af70c..ec4721e 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -298,6 +298,7 @@ const STR = { claimBtn: 'Claim it', claimFeeNote: '~{n} fee', claimFailed: 'This gift has already been claimed or is no longer available.', + claimNotVisibleBody: 'The coins funding this gift aren\u2019t visible from this wallet\u2019s network/data source. Make sure this wallet uses the same network and data source as the sender, then try again.', claimedTitle: 'Claimed!', claimedBody: 'Your Bitcoin is on its way. Back up your recovery phrase to keep it safe.', recoveryWarn: '⚠ Anyone who can see these words can steal your funds. Make sure nobody is watching before you reveal them.', |
