From ba2fbfe2901db35bb0cc688757f7e88dc52ff7b6 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 15 Feb 2026 16:58:08 -0800 Subject: fix custodial bitcoin sends --- lib/ark.ts | 16 +++++++++++----- routes/payments.ts | 24 +++++++++++++++++------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/lib/ark.ts b/lib/ark.ts index 52f441d7..3522c9cf 100644 --- a/lib/ark.ts +++ b/lib/ark.ts @@ -24,6 +24,7 @@ const getWallet = async () => { }; let refreshing = false; +const failedBoardingOutpoints = new Set(); const withTimeout = (promise: Promise, ms: number, label: string) => Promise.race([ @@ -89,11 +90,14 @@ export const refreshArkWallet = async () => { const info = await provider.getInfo(); const ramps = new Ramps(w); - // Try each boarding UTXO, freshest first - const sorted = [...confirmed].sort( - (a: any, b: any) => - (b.status?.block_height || 0) - (a.status?.block_height || 0), - ); + // Try each boarding UTXO, freshest first, skipping known failures + const outpointKey = (u: any) => `${u.txid}:${u.vout}`; + const sorted = [...confirmed] + .filter((u: any) => !failedBoardingOutpoints.has(outpointKey(u))) + .sort( + (a: any, b: any) => + (b.status?.block_height || 0) - (a.status?.block_height || 0), + ); for (const utxo of sorted) { try { @@ -103,8 +107,10 @@ export const refreshArkWallet = async () => { "ark onboard", ); l("ark onboarded boarding utxo:", utxo.value, "sats, txid:", txid); + failedBoardingOutpoints.clear(); break; } catch (e: any) { + failedBoardingOutpoints.add(outpointKey(utxo)); warn("ark onboard failed:", utxo.value, "sats:", e.message); } } diff --git a/routes/payments.ts b/routes/payments.ts index 6bed1309..4bdd0d30 100644 --- a/routes/payments.ts +++ b/routes/payments.ts @@ -89,13 +89,23 @@ export default { aid, }); } else { - p = await sendInternal({ - invoice, - amount, - memo, - recipient, - sender: user, - }); + // Check if recipient account is non-custodial (vault) + const recipientAccount = invoice?.aid ? await g(`account:${invoice.aid}`) : null; + if (recipientAccount?.pubkey || recipientAccount?.seed) { + p = await sendOnchain({ + amount: amount || invoice.amount, + address: invoice.hash, + user, + }); + } else { + p = await sendInternal({ + invoice, + amount, + memo, + recipient, + sender: user, + }); + } } } else if (fund) { p = await debit({ -- cgit v1.2.3