diff options
| author | Adam Soltys <[email protected]> | 2026-03-01 12:42:16 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-03-01 12:42:16 -0800 |
| commit | 0167d3d9348d9e2cb1f85cd499ef346f6e85dad1 (patch) | |
| tree | 8c3048fdf0f4209618ff7a4cb2be612856d3780b /src/lib | |
| parent | 6ac0d3da9668149cb2c3b6322fa431a2f7f508a9 (diff) | |
| download | coinos-ui-0167d3d9348d9e2cb1f85cd499ef346f6e85dad1.tar.gz coinos-ui-0167d3d9348d9e2cb1f85cd499ef346f6e85dad1.zip | |
Fix ark e2e tests: consolidate into serial suite, fix VTXO contention
- Skip settle/refresh during tests via ark:skipSettle flag to prevent
VTXOs from being registered in never-completing ark rounds
- Add 3s timeout on syncPromise wait in sendArk to prevent hangs
- Fix ensureArkAccount to wait for autoUnlockArk and create account
via API with correct address (Schnorr signatures are non-deterministic)
- Consolidate all 6 ark tests into single serial file to prevent
server wallet contention
- Split playwright config into parallel (non-ark) and serial (ark) projects
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/ark.ts | 42 |
1 files changed, 25 insertions, 17 deletions
diff --git a/src/lib/ark.ts b/src/lib/ark.ts index b59baa04..f6e34cdc 100644 --- a/src/lib/ark.ts +++ b/src/lib/ark.ts @@ -354,7 +354,7 @@ export const sendArk = async (address: string, amount: number) => { // Suppress sync polling and wait for any in-flight sync to finish arkSending = true; - if (syncPromise) await syncPromise.catch(() => {}); + if (syncPromise) await Promise.race([syncPromise.catch(() => {}), new Promise((r) => setTimeout(r, 3_000))]); try { // Refresh expired VTXOs before attempting to send @@ -371,28 +371,36 @@ export const sendArk = async (address: string, amount: number) => { let txid; let sendWallet = wallet; - try { - txid = await withTimeout(wallet.sendBitcoin({ address, amount }), 45_000, "Ark send"); - } catch (e: any) { - if ( - e?.message?.includes("VTXO_ALREADY_REGISTERED") || - e?.message?.includes("VTXO_ALREADY_SPENT") - ) { - walletInstance = undefined; - walletKey = undefined; - sendWallet = await getWallet(); - if (!sendWallet) throw new Error("Ark wallet not available after refresh"); - const vtxos = await sendWallet.getVtxos({ spendableOnly: false }); - if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey)); + // Retry loop for VTXO_ALREADY_REGISTERED — settle() may have registered VTXOs in a + // pending round. Wait for the round to abort (~5s) so VTXOs become unregistered. + for (let attempt = 0; attempt < 3; attempt++) { + try { txid = await withTimeout( sendWallet.sendBitcoin({ address, amount }), 45_000, - "Ark send retry", + "Ark send", ); - } else { - throw e; + break; + } catch (e: any) { + if ( + e?.message?.includes("VTXO_ALREADY_REGISTERED") || + e?.message?.includes("VTXO_ALREADY_SPENT") + ) { + console.log(`ark send attempt ${attempt + 1} failed:`, e.message, "— retrying"); + walletInstance = undefined; + walletKey = undefined; + sendWallet = await getWallet(); + if (!sendWallet) throw new Error("Ark wallet not available after refresh"); + const vtxos = await sendWallet.getVtxos({ spendableOnly: false }); + if (vtxos?.length) addProcessedVtxos(vtxos.map(vtxoKey)); + // Wait for the current round to abort before retrying + if (attempt < 2) await new Promise((r) => setTimeout(r, 6_000)); + } else { + throw e; + } } } + if (!txid) throw new Error("Ark send failed after retries"); // Verify the send and mark VTXOs as processed, but don't let // stalled SDK calls block the flow — the send already succeeded |
