aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-28 22:23:43 -0700
committerAdam Soltys <[email protected]>2026-06-28 22:23:43 -0700
commit677eea94b433685c4aa5f18c2ad9f18218cab30d (patch)
treeb61721aa78d560500d03a30e541438f5add83afb
parentfcd971da0c110607ccdc7637667beb0fa79d42a7 (diff)
downloadcoinosv3-677eea94b433685c4aa5f18c2ad9f18218cab30d.tar.gz
coinosv3-677eea94b433685c4aa5f18c2ad9f18218cab30d.zip
Swaps: mark a submarine swap done at invoice.paid, not transaction.claimed
A submarine swap's success is invoice.paid — Boltz has paid the Lightning invoice, which is the whole point and irreversible. Boltz then claims its on-chain lockup (transaction.claim.pending → claimed), often deferred to a later batch, so the old done-set ({transaction.claimed, invoice.settled}) left Hal stuck showing 'paying / waiting for Boltz to pay' indefinitely after the payment had already gone through. Add invoice.paid + transaction.claim.pending to the done set. Verified: a live swap stuck at transaction.claim.pending flips to 'success · Invoice paid ✓' after the fix. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
-rw-r--r--src/swap.js6
1 files changed, 5 insertions, 1 deletions
diff --git a/src/swap.js b/src/swap.js
index de89214..81336f4 100644
--- a/src/swap.js
+++ b/src/swap.js
@@ -331,7 +331,11 @@ export class SwapManager {
_watchSubmarine(id) {
if (this.timers.has(id)) return;
- const done = new Set(['transaction.claimed', 'invoice.settled']);
+ // For a submarine swap the success moment is invoice.paid — Boltz has paid the
+ // Lightning invoice (the whole point). It then claims its on-chain lockup
+ // (transaction.claim.pending → claimed), often deferred to a later batch, but
+ // our funds are already gone to the LN destination, so we're done either way.
+ const done = new Set(['invoice.paid', 'transaction.claim.pending', 'transaction.claimed', 'invoice.settled']);
const bad = new Set(['invoice.failedToPay', 'swap.expired', 'transaction.lockupFailed', 'transaction.refunded']);
const tick = async () => {
const rec = this._get(id);