From eb299830a2611a45e997bc729176ede81c5eead2 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 24 Jun 2026 13:47:11 -0700 Subject: Make gift Reclaim a real on-chain revoke The old "Reclaim" only un-reserved the coin locally, so the gift link stayed claimable. Replace it with "Revoke": a confirmed action that sweeps the reserved coin back into the sender's own wallet at a high fee (wallet.revokeGift), double-spending the gift's presigned input so the link can't be claimed once it confirms. Races a simultaneous claimer; if the gift was already claimed the broadcast just fails. New strings translated across all 19 locales. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/wallet.js | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/wallet.js') diff --git a/src/wallet.js b/src/wallet.js index 06af3dc..b5945ff 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -787,6 +787,17 @@ export class Wallet { this.reservedSet().delete(id); this._saveReserved(); } + + // Truly revoke an unclaimed gift: spend its coin back into our own wallet, + // which double-spends the gift's presigned input so the link can't be claimed + // once this confirms. Uses a high fee to win any race with a claimer. + async revokeGift(id, feeRate) { + const draft = this.buildTx({ recipients: [{ address: this.freshChange().address }], feeRate, coinIds: [id], sendMax: true }); + const hexTx = this.sign(draft.tx); + const txid = await this.broadcast(hexTx); + this.unreserve(id); + return txid; + } // Active gifts whose coin is still unspent (drops claimed/spent ones). activeGifts() { const live = new Set(this.utxos.map((u) => utxoId(u))); -- cgit v1.2.3