diff options
| author | Adam Soltys <[email protected]> | 2026-02-15 16:58:08 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-02-15 16:58:08 -0800 |
| commit | ba2fbfe2901db35bb0cc688757f7e88dc52ff7b6 (patch) | |
| tree | 372e2911aeeb0e770a749e37d818a55a9e79cad3 | |
| parent | 4d3377ba1d37147b194c1fb0504edee3c73211a5 (diff) | |
| download | coinos-server-ba2fbfe2901db35bb0cc688757f7e88dc52ff7b6.tar.gz coinos-server-ba2fbfe2901db35bb0cc688757f7e88dc52ff7b6.zip | |
fix custodial bitcoin sends
| -rw-r--r-- | lib/ark.ts | 16 | ||||
| -rw-r--r-- | routes/payments.ts | 24 |
2 files changed, 28 insertions, 12 deletions
@@ -24,6 +24,7 @@ const getWallet = async () => { }; let refreshing = false; +const failedBoardingOutpoints = new Set<string>(); const withTimeout = <T>(promise: Promise<T>, 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({ |
