From 46cbe94159fe65d8cb6a944b52a9ead6c53e7a3c Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sat, 1 Aug 2026 15:45:55 -0700 Subject: Reconcile vtxos against the server before a headless NWC payment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sync merge is additive by design, so a vtxo spent on one device can survive in another device's state looking spendable. The interactive send path reconciles on intent; the NWC path connected and spent blind, so a wallet answering from stale state picked an already-spent coin and the ASP refused with 'vtxo … is not spendable (state: spent)'. Co-Authored-By: Claude Fable 5 --- src/features/ark.js | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/features') diff --git a/src/features/ark.js b/src/features/ark.js index 9621c4b..1c0ad1b 100644 --- a/src/features/ark.js +++ b/src/features/ark.js @@ -554,6 +554,11 @@ export function arkFeature(ctx) { throw new Error(`amount ${dec.amountSat} exceeds the limit of ${maxAmountSat} sat`); } const mgr = await connectArk(); + // The sync merge is additive, so a vtxo spent on another device can sit + // in local state looking spendable until someone checks. The interactive + // send path reconciles on intent; this headless path must too, or an NWC + // payment picks the stale coin and the ASP rejects it ("state: spent"). + await mgr.reconcile().catch(() => {}); // 1. the bridge, when one is configured and can take it try { -- cgit v1.2.3