@miradexio/client 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/README.md +57 -292
  2. package/dist/address/base58.d.ts.map +1 -1
  3. package/dist/address/base58.js +1 -2
  4. package/dist/address/base58.js.map +1 -1
  5. package/dist/address/bech32.d.ts +0 -8
  6. package/dist/address/bech32.d.ts.map +1 -1
  7. package/dist/address/bech32.js +3 -9
  8. package/dist/address/bech32.js.map +1 -1
  9. package/dist/address/evm.d.ts.map +1 -1
  10. package/dist/address/evm.js +1 -2
  11. package/dist/address/evm.js.map +1 -1
  12. package/dist/address/index.d.ts +0 -6
  13. package/dist/address/index.d.ts.map +1 -1
  14. package/dist/address/index.js +6 -9
  15. package/dist/address/index.js.map +1 -1
  16. package/dist/address/monero.d.ts +0 -10
  17. package/dist/address/monero.d.ts.map +1 -1
  18. package/dist/address/monero.js +4 -10
  19. package/dist/address/monero.js.map +1 -1
  20. package/dist/address/polkadot.d.ts +0 -5
  21. package/dist/address/polkadot.d.ts.map +1 -1
  22. package/dist/address/polkadot.js +2 -6
  23. package/dist/address/polkadot.js.map +1 -1
  24. package/dist/address/ton.d.ts +0 -6
  25. package/dist/address/ton.d.ts.map +1 -1
  26. package/dist/address/ton.js +3 -8
  27. package/dist/address/ton.js.map +1 -1
  28. package/dist/api/index.d.ts +0 -19
  29. package/dist/api/index.d.ts.map +1 -1
  30. package/dist/api/index.js +18 -37
  31. package/dist/api/index.js.map +1 -1
  32. package/dist/atomic-swap/drive.d.ts +0 -13
  33. package/dist/atomic-swap/drive.d.ts.map +1 -1
  34. package/dist/atomic-swap/drive.js +72 -114
  35. package/dist/atomic-swap/drive.js.map +1 -1
  36. package/dist/atomic-swap/extract.d.ts +0 -23
  37. package/dist/atomic-swap/extract.d.ts.map +1 -1
  38. package/dist/atomic-swap/extract.js +6 -16
  39. package/dist/atomic-swap/extract.js.map +1 -1
  40. package/dist/atomic-swap/index.d.ts +0 -7
  41. package/dist/atomic-swap/index.d.ts.map +1 -1
  42. package/dist/atomic-swap/index.js +1 -7
  43. package/dist/atomic-swap/index.js.map +1 -1
  44. package/dist/atomic-swap/monero-sweep/errors.d.ts.map +1 -1
  45. package/dist/atomic-swap/monero-sweep/errors.js +5 -20
  46. package/dist/atomic-swap/monero-sweep/errors.js.map +1 -1
  47. package/dist/atomic-swap/monero-sweep/index.d.ts +1 -13
  48. package/dist/atomic-swap/monero-sweep/index.d.ts.map +1 -1
  49. package/dist/atomic-swap/monero-sweep/index.js +36 -65
  50. package/dist/atomic-swap/monero-sweep/index.js.map +1 -1
  51. package/dist/atomic-swap/monero-sweep/ring-select.d.ts +0 -4
  52. package/dist/atomic-swap/monero-sweep/ring-select.d.ts.map +1 -1
  53. package/dist/atomic-swap/monero-sweep/ring-select.js +9 -21
  54. package/dist/atomic-swap/monero-sweep/ring-select.js.map +1 -1
  55. package/dist/atomic-swap/presign.d.ts +0 -63
  56. package/dist/atomic-swap/presign.d.ts.map +1 -1
  57. package/dist/atomic-swap/presign.js +30 -90
  58. package/dist/atomic-swap/presign.js.map +1 -1
  59. package/dist/atomic-swap/refund.d.ts +0 -18
  60. package/dist/atomic-swap/refund.d.ts.map +1 -1
  61. package/dist/atomic-swap/refund.js +16 -32
  62. package/dist/atomic-swap/refund.js.map +1 -1
  63. package/dist/atomic-swap/run.d.ts +0 -17
  64. package/dist/atomic-swap/run.d.ts.map +1 -1
  65. package/dist/atomic-swap/run.js +11 -25
  66. package/dist/atomic-swap/run.js.map +1 -1
  67. package/dist/atomic-swap/snapshot.d.ts +0 -30
  68. package/dist/atomic-swap/snapshot.d.ts.map +1 -1
  69. package/dist/atomic-swap/snapshot.js +8 -23
  70. package/dist/atomic-swap/snapshot.js.map +1 -1
  71. package/dist/atomic-swap/submit-encsig.d.ts +0 -7
  72. package/dist/atomic-swap/submit-encsig.d.ts.map +1 -1
  73. package/dist/atomic-swap/submit-encsig.js +8 -15
  74. package/dist/atomic-swap/submit-encsig.js.map +1 -1
  75. package/dist/atomic-swap/types.d.ts +2 -55
  76. package/dist/atomic-swap/types.d.ts.map +1 -1
  77. package/dist/atomic-swap/types.js +2 -3
  78. package/dist/atomic-swap/types.js.map +1 -1
  79. package/dist/blockchain/quorum-provider.d.ts +0 -15
  80. package/dist/blockchain/quorum-provider.d.ts.map +1 -1
  81. package/dist/blockchain/quorum-provider.js +7 -9
  82. package/dist/blockchain/quorum-provider.js.map +1 -1
  83. package/dist/cooperative-redeem.d.ts +5 -14
  84. package/dist/cooperative-redeem.d.ts.map +1 -1
  85. package/dist/cooperative-redeem.js +3 -20
  86. package/dist/cooperative-redeem.js.map +1 -1
  87. package/dist/engine/blockchain-querier.d.ts +0 -22
  88. package/dist/engine/blockchain-querier.d.ts.map +1 -1
  89. package/dist/engine/engine-state.d.ts +0 -8
  90. package/dist/engine/engine-state.d.ts.map +1 -1
  91. package/dist/engine/engine-state.js.map +1 -1
  92. package/dist/engine/flow-context.d.ts +0 -20
  93. package/dist/engine/flow-context.d.ts.map +1 -1
  94. package/dist/engine/flow-context.js +17 -41
  95. package/dist/engine/flow-context.js.map +1 -1
  96. package/dist/engine/flows/atomic-flow-state.d.ts +8 -1
  97. package/dist/engine/flows/atomic-flow-state.d.ts.map +1 -1
  98. package/dist/engine/flows/atomic-flow.d.ts +1 -28
  99. package/dist/engine/flows/atomic-flow.d.ts.map +1 -1
  100. package/dist/engine/flows/atomic-flow.js +98 -128
  101. package/dist/engine/flows/atomic-flow.js.map +1 -1
  102. package/dist/engine/flows/error-routing.d.ts +11 -0
  103. package/dist/engine/flows/error-routing.d.ts.map +1 -0
  104. package/dist/engine/flows/error-routing.js +17 -0
  105. package/dist/engine/flows/error-routing.js.map +1 -0
  106. package/dist/engine/flows/swap-flow.d.ts +0 -19
  107. package/dist/engine/flows/swap-flow.d.ts.map +1 -1
  108. package/dist/engine/flows/swap-flow.js +41 -83
  109. package/dist/engine/flows/swap-flow.js.map +1 -1
  110. package/dist/engine/miradex-engine.d.ts +1 -62
  111. package/dist/engine/miradex-engine.d.ts.map +1 -1
  112. package/dist/engine/miradex-engine.js +18 -50
  113. package/dist/engine/miradex-engine.js.map +1 -1
  114. package/dist/engine/pipeline.d.ts +0 -11
  115. package/dist/engine/pipeline.d.ts.map +1 -1
  116. package/dist/engine/pipeline.js +11 -21
  117. package/dist/engine/pipeline.js.map +1 -1
  118. package/dist/engine/platform.d.ts +0 -160
  119. package/dist/engine/platform.d.ts.map +1 -1
  120. package/dist/engine/platform.js +2 -0
  121. package/dist/engine/platform.js.map +1 -1
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js +7 -11
  124. package/dist/index.js.map +1 -1
  125. package/dist/interfaces/blockchain.d.ts +1 -13
  126. package/dist/interfaces/blockchain.d.ts.map +1 -1
  127. package/dist/interfaces/blockchain.js +1 -0
  128. package/dist/interfaces/blockchain.js.map +1 -1
  129. package/dist/interfaces/logger.d.ts +0 -6
  130. package/dist/interfaces/logger.d.ts.map +1 -1
  131. package/dist/interfaces/logger.js.map +1 -1
  132. package/dist/lib/bitcoin/deposit-watcher.d.ts +0 -23
  133. package/dist/lib/bitcoin/deposit-watcher.d.ts.map +1 -1
  134. package/dist/lib/bitcoin/deposit-watcher.js +7 -31
  135. package/dist/lib/bitcoin/deposit-watcher.js.map +1 -1
  136. package/dist/lib/bitcoin/script-hash.d.ts.map +1 -1
  137. package/dist/lib/bitcoin/script-hash.js +2 -6
  138. package/dist/lib/bitcoin/script-hash.js.map +1 -1
  139. package/dist/lib/bitcoin/sweep.d.ts +0 -30
  140. package/dist/lib/bitcoin/sweep.d.ts.map +1 -1
  141. package/dist/lib/bitcoin/sweep.js +11 -40
  142. package/dist/lib/bitcoin/sweep.js.map +1 -1
  143. package/dist/lib/bitcoin/tx-verify.d.ts +0 -28
  144. package/dist/lib/bitcoin/tx-verify.d.ts.map +1 -1
  145. package/dist/lib/bitcoin/tx-verify.js +20 -61
  146. package/dist/lib/bitcoin/tx-verify.js.map +1 -1
  147. package/dist/lib/bitcoin/wallet.d.ts +0 -38
  148. package/dist/lib/bitcoin/wallet.d.ts.map +1 -1
  149. package/dist/lib/bitcoin/wallet.js +13 -38
  150. package/dist/lib/bitcoin/wallet.js.map +1 -1
  151. package/dist/lib/crypto/bytes.d.ts +0 -14
  152. package/dist/lib/crypto/bytes.d.ts.map +1 -1
  153. package/dist/lib/crypto/bytes.js +5 -14
  154. package/dist/lib/crypto/bytes.js.map +1 -1
  155. package/dist/lib/crypto/errors.d.ts +0 -5
  156. package/dist/lib/crypto/errors.d.ts.map +1 -1
  157. package/dist/lib/crypto/errors.js +2 -5
  158. package/dist/lib/crypto/errors.js.map +1 -1
  159. package/dist/lib/crypto/libp2p-identity.d.ts +0 -15
  160. package/dist/lib/crypto/libp2p-identity.d.ts.map +1 -1
  161. package/dist/lib/crypto/libp2p-identity.js +16 -28
  162. package/dist/lib/crypto/libp2p-identity.js.map +1 -1
  163. package/dist/lib/crypto/mnemonic.d.ts +0 -9
  164. package/dist/lib/crypto/mnemonic.d.ts.map +1 -1
  165. package/dist/lib/crypto/mnemonic.js +11 -27
  166. package/dist/lib/crypto/mnemonic.js.map +1 -1
  167. package/dist/lib/crypto/platform.d.ts +0 -6
  168. package/dist/lib/crypto/platform.d.ts.map +1 -1
  169. package/dist/lib/crypto/platform.js +2 -6
  170. package/dist/lib/crypto/platform.js.map +1 -1
  171. package/dist/lib/crypto/scalars.d.ts +0 -23
  172. package/dist/lib/crypto/scalars.d.ts.map +1 -1
  173. package/dist/lib/crypto/scalars.js +10 -23
  174. package/dist/lib/crypto/scalars.js.map +1 -1
  175. package/dist/lib/crypto/types.d.ts +0 -4
  176. package/dist/lib/crypto/types.d.ts.map +1 -1
  177. package/dist/lib/crypto/wasm.d.ts +0 -23
  178. package/dist/lib/crypto/wasm.d.ts.map +1 -1
  179. package/dist/lib/crypto/wasm.js +9 -16
  180. package/dist/lib/crypto/wasm.js.map +1 -1
  181. package/dist/lib/default-config.d.ts +1 -59
  182. package/dist/lib/default-config.d.ts.map +1 -1
  183. package/dist/lib/default-config.js +22 -61
  184. package/dist/lib/default-config.js.map +1 -1
  185. package/dist/lib/errors.d.ts +0 -54
  186. package/dist/lib/errors.d.ts.map +1 -1
  187. package/dist/lib/errors.js +12 -35
  188. package/dist/lib/errors.js.map +1 -1
  189. package/dist/lib/keystore.d.ts +0 -24
  190. package/dist/lib/keystore.d.ts.map +1 -1
  191. package/dist/lib/keystore.js +3 -10
  192. package/dist/lib/keystore.js.map +1 -1
  193. package/dist/lib/monero/output-scanner.d.ts +0 -18
  194. package/dist/lib/monero/output-scanner.d.ts.map +1 -1
  195. package/dist/lib/monero/output-scanner.js +17 -40
  196. package/dist/lib/monero/output-scanner.js.map +1 -1
  197. package/dist/lib/monero/rpc.d.ts +0 -64
  198. package/dist/lib/monero/rpc.d.ts.map +1 -1
  199. package/dist/lib/monero/rpc.js +17 -59
  200. package/dist/lib/monero/rpc.js.map +1 -1
  201. package/dist/lib/monero/verify-lock.d.ts +0 -12
  202. package/dist/lib/monero/verify-lock.d.ts.map +1 -1
  203. package/dist/lib/monero/verify-lock.js +9 -24
  204. package/dist/lib/monero/verify-lock.js.map +1 -1
  205. package/dist/lib/monero/verify-sweep.d.ts +0 -20
  206. package/dist/lib/monero/verify-sweep.d.ts.map +1 -1
  207. package/dist/lib/monero/verify-sweep.js +7 -25
  208. package/dist/lib/monero/verify-sweep.js.map +1 -1
  209. package/dist/lib/pow-solver.d.ts.map +1 -1
  210. package/dist/lib/pow-solver.js +3 -8
  211. package/dist/lib/pow-solver.js.map +1 -1
  212. package/dist/lib/retry.d.ts +7 -64
  213. package/dist/lib/retry.d.ts.map +1 -1
  214. package/dist/lib/retry.js +13 -13
  215. package/dist/lib/retry.js.map +1 -1
  216. package/dist/portable.d.ts.map +1 -1
  217. package/dist/portable.js +3 -4
  218. package/dist/portable.js.map +1 -1
  219. package/dist/quote-binding.d.ts +0 -13
  220. package/dist/quote-binding.d.ts.map +1 -1
  221. package/dist/quote-binding.js +3 -18
  222. package/dist/quote-binding.js.map +1 -1
  223. package/dist/swap-executor.d.ts +1 -5
  224. package/dist/swap-executor.d.ts.map +1 -1
  225. package/dist/swap-executor.js +1 -1
  226. package/dist/swap-executor.js.map +1 -1
  227. package/dist/types/api.d.ts +0 -6
  228. package/dist/types/api.d.ts.map +1 -1
  229. package/dist/types/api.js +6 -9
  230. package/dist/types/api.js.map +1 -1
  231. package/dist/types/errors.d.ts +0 -7
  232. package/dist/types/errors.d.ts.map +1 -1
  233. package/dist/types/errors.js +2 -7
  234. package/dist/types/errors.js.map +1 -1
  235. package/dist/types/index.js +1 -1
  236. package/dist/types/index.js.map +1 -1
  237. package/dist/types/keys.d.ts +0 -15
  238. package/dist/types/keys.d.ts.map +1 -1
  239. package/dist/types/protocol.d.ts +0 -51
  240. package/dist/types/protocol.d.ts.map +1 -1
  241. package/dist/types/protocol.js +3 -8
  242. package/dist/types/protocol.js.map +1 -1
  243. package/dist/types/status.d.ts +2 -0
  244. package/dist/types/status.d.ts.map +1 -1
  245. package/dist/types/status.js +17 -14
  246. package/dist/types/status.js.map +1 -1
  247. package/dist/types/verification.d.ts +0 -10
  248. package/dist/types/verification.d.ts.map +1 -1
  249. package/dist/types/verification.js +7 -15
  250. package/dist/types/verification.js.map +1 -1
  251. package/dist/verification/chainflip-networks.d.ts +2 -35
  252. package/dist/verification/chainflip-networks.d.ts.map +1 -1
  253. package/dist/verification/chainflip-networks.js +12 -4
  254. package/dist/verification/chainflip-networks.js.map +1 -1
  255. package/dist/verification/chainflip.d.ts +0 -40
  256. package/dist/verification/chainflip.d.ts.map +1 -1
  257. package/dist/verification/chainflip.js +49 -129
  258. package/dist/verification/chainflip.js.map +1 -1
  259. package/dist/verification/constants.d.ts +0 -40
  260. package/dist/verification/constants.d.ts.map +1 -1
  261. package/dist/verification/constants.js +14 -40
  262. package/dist/verification/constants.js.map +1 -1
  263. package/dist/verification/index.d.ts +0 -26
  264. package/dist/verification/index.d.ts.map +1 -1
  265. package/dist/verification/index.js +8 -12
  266. package/dist/verification/index.js.map +1 -1
  267. package/dist/verification/memo.d.ts +0 -15
  268. package/dist/verification/memo.d.ts.map +1 -1
  269. package/dist/verification/memo.js +9 -27
  270. package/dist/verification/memo.js.map +1 -1
  271. package/dist/verification/near-intents.d.ts +0 -63
  272. package/dist/verification/near-intents.d.ts.map +1 -1
  273. package/dist/verification/near-intents.js +25 -67
  274. package/dist/verification/near-intents.js.map +1 -1
  275. package/dist/verification/rate-oracle.d.ts +0 -22
  276. package/dist/verification/rate-oracle.d.ts.map +1 -1
  277. package/dist/verification/rate-oracle.js +6 -11
  278. package/dist/verification/rate-oracle.js.map +1 -1
  279. package/dist/verification/thorchain-networks.d.ts +0 -27
  280. package/dist/verification/thorchain-networks.d.ts.map +1 -1
  281. package/dist/verification/thorchain-networks.js +13 -15
  282. package/dist/verification/thorchain-networks.js.map +1 -1
  283. package/dist/verification/thorchain.d.ts +0 -30
  284. package/dist/verification/thorchain.d.ts.map +1 -1
  285. package/dist/verification/thorchain.js +24 -47
  286. package/dist/verification/thorchain.js.map +1 -1
  287. package/dist/wasm-pins.d.ts +3 -3
  288. package/dist/wasm-pins.js +1 -1
  289. package/dist/wire/near-intents.zod.d.ts +0 -27
  290. package/dist/wire/near-intents.zod.d.ts.map +1 -1
  291. package/dist/wire/near-intents.zod.js +15 -23
  292. package/dist/wire/near-intents.zod.js.map +1 -1
  293. package/dist/wire/server/action.zod.d.ts +0 -10
  294. package/dist/wire/server/action.zod.d.ts.map +1 -1
  295. package/dist/wire/server/action.zod.js +8 -14
  296. package/dist/wire/server/action.zod.js.map +1 -1
  297. package/dist/wire/server/common.zod.d.ts +0 -13
  298. package/dist/wire/server/common.zod.d.ts.map +1 -1
  299. package/dist/wire/server/common.zod.js +6 -14
  300. package/dist/wire/server/common.zod.js.map +1 -1
  301. package/dist/wire/server/quotes.zod.d.ts +35 -20
  302. package/dist/wire/server/quotes.zod.d.ts.map +1 -1
  303. package/dist/wire/server/quotes.zod.js +1 -0
  304. package/dist/wire/server/quotes.zod.js.map +1 -1
  305. package/dist/wire/server/swap.zod.d.ts +0 -42
  306. package/dist/wire/server/swap.zod.d.ts.map +1 -1
  307. package/dist/wire/server/swap.zod.js +12 -26
  308. package/dist/wire/server/swap.zod.js.map +1 -1
  309. package/dist/wire/thorchain.zod.d.ts +0 -8
  310. package/dist/wire/thorchain.zod.d.ts.map +1 -1
  311. package/dist/wire/thorchain.zod.js +3 -8
  312. package/dist/wire/thorchain.zod.js.map +1 -1
  313. package/package.json +4 -4
  314. package/wasm/miradex-rust/README.md +3 -4
  315. package/wasm/miradex-rust/miradex_rust.d.ts +4 -6
  316. package/wasm/miradex-rust/miradex_rust.js +4 -6
  317. package/wasm/miradex-rust/miradex_rust_bg.wasm +0 -0
@@ -1,5 +1,6 @@
1
1
  import { ApiError, NetworkError } from '../../api/index.js';
2
2
  import { TERMINAL_STATUSES, ProtocolError } from '../../types/index.js';
3
+ import { routeError } from './error-routing.js';
3
4
  import { createFlowContext, mergeFlowContext, validatePopulated, validateVerified, } from '../flow-context.js';
4
5
  import { resumeAtomicSwap as coreResumeAtomicSwap, SwapCancelledError, } from '../../atomic-swap/index.js';
5
6
  import { generateMnemonicKeys } from '../../lib/crypto/mnemonic.js';
@@ -16,6 +17,15 @@ import { buildMultisigWitnessScript } from '../../atomic-swap/presign.js';
16
17
  import { extractProtocolData } from '../../atomic-swap/extract.js';
17
18
  const DEFAULT_POLL_MS = 5_000;
18
19
  const MAX_TRANSIENT_RETRIES = 5;
20
+ const SWAP_STATUS_STAGES = new Set([
21
+ 'pending',
22
+ 'awaiting_funding',
23
+ 'initializing',
24
+ 'deposited',
25
+ 'swapping',
26
+ 'sending',
27
+ 'punished',
28
+ ]);
19
29
  function isTransientError(err) {
20
30
  if (err instanceof NetworkError)
21
31
  return true;
@@ -27,16 +37,14 @@ function isTransientError(err) {
27
37
  }
28
38
  return false;
29
39
  }
30
- /**
31
- * True iff the protocol params carry enough material for the client to
32
- * construct a refund without sidecar cooperation. Two valid shapes:
33
- * - Legacy/Full: `tx_full_refund_encsig` alone is enough — the client
34
- * builds and broadcasts TxFullRefund spending TxCancel.
35
- * - Partial (amnesty): `tx_partial_refund_encsig` plus the amnesty
36
- * triple (`amnesty_amount_sats`, `tx_partial_refund_fee_sats`) drive
37
- * the partial-refund branch. The amnesty output stays at multisig
38
- * until a separate TxReclaim phase (not yet implemented client-side).
39
- */
40
+ // True if the params carry enough material to refund without the sidecar.
41
+ // Two valid shapes:
42
+ // Legacy/Full: tx_full_refund_encsig alone (client builds + broadcasts
43
+ // TxFullRefund spending TxCancel).
44
+ // Partial: tx_partial_refund_encsig + amnesty triple
45
+ // (amnesty_amount_sats, tx_partial_refund_fee_sats). Amnesty
46
+ // output stays at multisig pending TxReclaim (not implemented
47
+ // client-side yet).
40
48
  function hasRefundEscapeHatch(params) {
41
49
  if (params.tx_full_refund_encsig)
42
50
  return true;
@@ -59,22 +67,15 @@ export class AtomicFlow {
59
67
  lastEmittedState = { phase: 'idle', snapshot: null };
60
68
  flowCtx = null;
61
69
  lastProgressKey = null;
70
+ lastSeenStatus = null;
62
71
  pollMs;
63
- /**
64
- * True once the driver has emitted a terminal phase (`completed`,
65
- * `failed`, `refunded`, etc.). Used to suppress the post-driver
66
- * `requiredAction` re-check that would otherwise trigger a phantom
67
- * second sweep — the server has no scanner for the on-chain XMR sweep,
68
- * so a fresh `getSwapDetail` right after the driver completes still
69
- * reports `requiredAction.type === 'sweep'`.
70
- */
72
+ // Set once the driver emits a terminal phase. Suppresses the post-driver
73
+ // requiredAction re-check that would otherwise trigger a phantom second
74
+ // sweep the server has no scanner for the on-chain XMR sweep so a fresh
75
+ // getSwapDetail still reports requiredAction.type === 'sweep'.
71
76
  hasReachedTerminal = false;
72
- /**
73
- * Optional maker pin forwarded to `coreResumeAtomicSwap` via
74
- * `params.variantId`. Set by `start()` from `StartAtomicSwapParams`;
75
- * unused (and irrelevant) on the resume path because the maker is
76
- * already chosen at that point.
77
- */
77
+ // Forwarded to coreResumeAtomicSwap as params.variantId. Set by start();
78
+ // ignored on resume (maker already chosen).
78
79
  variantId;
79
80
  constructor(api, platform, config, emitFn, options) {
80
81
  this.api = api;
@@ -94,10 +95,7 @@ export class AtomicFlow {
94
95
  ? mergeFlowContext(this.flowCtx, partial)
95
96
  : createFlowContext(partial);
96
97
  }
97
- /**
98
- * Validate FlowContext as PopulatedFlowContext.
99
- * On failure, emits a 'failed' phase with structured error and returns null.
100
- */
98
+ // On failure, emits 'failed' with a structured error and returns null.
101
99
  requirePopulated(phase) {
102
100
  if (!this.flowCtx) {
103
101
  this.emitError(phase, 'FlowContext not initialized');
@@ -110,10 +108,7 @@ export class AtomicFlow {
110
108
  this.emitError(phase, result.error.message);
111
109
  return null;
112
110
  }
113
- /**
114
- * Validate FlowContext as VerifiedFlowContext.
115
- * On failure, emits a 'failed' phase with structured error and returns null.
116
- */
111
+ // On failure, emits 'failed' with a structured error and returns null.
117
112
  requireVerified(phase) {
118
113
  if (!this.flowCtx) {
119
114
  this.emitError(phase, 'FlowContext not initialized');
@@ -168,17 +163,14 @@ export class AtomicFlow {
168
163
  this.transition({ phase: 'keygen', snapshot: this.flowCtx, message: 'Initializing keygen...' });
169
164
  await ensureWasm();
170
165
  const network = this.config.network;
171
- // Either reuse an existing keystore (re-quote-after-failure path) or
172
- // generate a fresh one (default path). In both cases the rest of the
173
- // flow is identical from this point forward — same deposit polling,
174
- // same swap creation, same drive loop.
166
+ // Reuse an existing keystore (re-quote-after-failure) or generate a
167
+ // fresh one. Flow is identical past this point.
175
168
  let wallet;
176
169
  if (params.existingKeystoreId !== undefined) {
177
170
  this.setFlowContext({ extra: { text: 'Loading keystore...', type: 'message' } });
178
171
  this.transition({ phase: 'keygen', snapshot: this.flowCtx, message: 'Loading keystore...' });
179
- // Trust: the keystore was created here originally and its keys
180
- // already passed `verifyKeys`. Skipping the API call avoids
181
- // doubling the call's transient-failure surface for a no-op check.
172
+ // Trust the keystore: it was created here and its keys already
173
+ // passed verifyKeys. Re-checking adds a transient-failure surface.
182
174
  this.keystore = await this.platform.loadKeystore(params.existingKeystoreId);
183
175
  this.keystoreId = params.existingKeystoreId;
184
176
  wallet = walletFromWif(this.keystore.btc.wif, network);
@@ -216,16 +208,10 @@ export class AtomicFlow {
216
208
  this.keystoreId = saveResult.id;
217
209
  this.logger.info({ keystoreId: this.keystoreId }, 'Keystore saved');
218
210
  }
219
- // Emit `keystoreId` to engine state IMMEDIATELY, before the slow
220
- // pre-deposit prep work (`estimateFee` mempool.space, `getQuotes`
221
- // swap-engine, `generateQr` wasm). The web app's
222
- // EngineRegistry races a 30 s timeout against `state.atomic.
223
- // snapshot.keystoreId` to decide whether to keep this engine; if
224
- // the slow chain below blows the budget the engine is destroyed
225
- // mid-flight and the user has to retry. Emitting a placeholder
226
- // keystore-saved transition here guarantees the registry binds
227
- // the engine on first save, regardless of subsequent network
228
- // latency.
211
+ // Emit keystoreId before the slow pre-deposit chain (estimateFee,
212
+ // getQuotes, generateQr). EngineRegistry races a 30s timeout against
213
+ // state.atomic.snapshot.keystoreId without this early emit the
214
+ // engine gets destroyed mid-flight on slow networks.
229
215
  this.setFlowContext({ keystoreId: this.keystoreId });
230
216
  this.transition({
231
217
  phase: 'keystore-saved',
@@ -244,12 +230,8 @@ export class AtomicFlow {
244
230
  }
245
231
  catch { /* non-fatal */ }
246
232
  const qr = await this.platform.generateQr(wallet.address);
247
- // Now that the slow chain has finished, populate the full
248
- // FlowContext with the deposit address, expected XMR amount, and
249
- // QR. The first `keystore-saved` transition above was the bare-
250
- // bones state emit needed to keep the registry from destroying
251
- // this engine; this second `setFlowContext` enriches it before
252
- // `awaiting-deposit` validates against `PopulatedFlowContext`.
233
+ // Slow chain done: enrich FlowContext before awaiting-deposit validates
234
+ // against PopulatedFlowContext.
253
235
  this.setFlowContext({
254
236
  depositAddr: wallet.address,
255
237
  depositAmount: requiredBtc,
@@ -258,7 +240,6 @@ export class AtomicFlow {
258
240
  extra: { text: `Send ${requiredBtc} BTC to the address above.`, type: 'message' },
259
241
  });
260
242
  this.checkAborted();
261
- // Validate before emitting awaiting-deposit
262
243
  const populated = this.requirePopulated('awaiting-deposit');
263
244
  if (!populated)
264
245
  return;
@@ -334,15 +315,10 @@ export class AtomicFlow {
334
315
  this.emitTerminal(existingSwapId, detail.status, detail);
335
316
  return;
336
317
  }
337
- // Funding-address UTXO is only meaningful pre-broadcast once the
338
- // swap is `deposited` or beyond, the BTC has already been swept
339
- // into TxLock at the lock address and the funding address is
340
- // empty. Re-querying it on every resume costs 2-15 s on
341
- // testnet/stagenet electrs (cold TLS, multi-server fallback,
342
- // flaky public endpoints) and the result feeds nothing
343
- // downstream once the protocol is past funding. Skip it for
344
- // post-funding statuses so resume settles immediately on the
345
- // current state instead of stalling on a useless network probe.
318
+ // Funding-address UTXO is only meaningful pre-broadcast; once the
319
+ // swap is 'deposited' or past, BTC is in TxLock and the funding
320
+ // address is empty. Re-querying costs 2-15s on flaky public
321
+ // electrs and feeds nothing downstream skip for post-funding.
346
322
  const PRE_FUNDING_STATUSES = new Set([
347
323
  'initializing',
348
324
  'pending',
@@ -353,7 +329,6 @@ export class AtomicFlow {
353
329
  : null;
354
330
  if (deposit)
355
331
  this.deposit = deposit;
356
- // Verify the contract for the resumed swap
357
332
  let verification = null;
358
333
  if (detail.depositAddress && detail.verification) {
359
334
  const { verifyDepositAddress } = await import('../../verification/index.js');
@@ -364,8 +339,7 @@ export class AtomicFlow {
364
339
  refundAddress: this.keystore.swap.refundAddress,
365
340
  toToken: 'XMR',
366
341
  amount: '',
367
- // Lock address lives at the top level of SwapDetail; timelock
368
- // blocks come from the typed atomicswap params when present.
342
+ // lock_address = SwapDetail.depositAddress; timelock from typed params.
369
343
  protocol: detail.depositAddress &&
370
344
  detail.protocolData?.type === 'atomicswap' &&
371
345
  detail.protocolData.params
@@ -379,7 +353,7 @@ export class AtomicFlow {
379
353
  fetchFn: this.config.fetchFn,
380
354
  });
381
355
  }
382
- // Fallback: if server has progressed past verification, trust it
356
+ // Server is past the verification gate; trust it.
383
357
  if (!verification) {
384
358
  verification = { verified: true, provider: 'atomicswap', checks: [], timestamp: Date.now() };
385
359
  }
@@ -390,8 +364,8 @@ export class AtomicFlow {
390
364
  depositAmount: deposit ? (deposit.value / 1e8).toFixed(8) : this.flowCtx?.depositAmount ?? null,
391
365
  extra: { text: `Resuming swap (${detail.status})...`, type: 'message' },
392
366
  });
393
- // For resumed swaps the core will provide verification via progress callbacks.
394
- // Emit as swapping (base FlowContext is sufficient for resume entry).
367
+ // Core supplies verification via progress callbacks on resume; base
368
+ // FlowContext is enough for the entry transition.
395
369
  this.transition({
396
370
  phase: 'creating-swap',
397
371
  snapshot: this.flowCtx,
@@ -402,10 +376,9 @@ export class AtomicFlow {
402
376
  }
403
377
  this.logger.info({ btcAddress }, 'Resume Path B: local keystore');
404
378
  const deposit = await this.platform.fetchUtxo(btcAddress, network);
405
- // Fetch expected XMR output for both branches (required for PopulatedFlowContext).
406
- // Pre-funding resume: there's no deposit yet, so we can't derive the
407
- // amount from on-chain. Read the original amount the swap was started
408
- // with from the keystore metadata (saved by saveKeystore as `label`).
379
+ // expectedOut is required for PopulatedFlowContext. Pre-funding resume
380
+ // has no on-chain deposit, so pull the original amount from the
381
+ // keystore metadata (saveKeystore stores it as `label`).
409
382
  let amountForQuote;
410
383
  if (deposit) {
411
384
  amountForQuote = (deposit.value / 1e8).toFixed(8);
@@ -522,9 +495,8 @@ export class AtomicFlow {
522
495
  throw new Error('keystore must be set before driving swap');
523
496
  }
524
497
  const network = (this.keystore.btc?.network ?? 'mainnet');
525
- // Provide a blockchain provider so the resume path can reconstruct the
526
- // TxLock from on-chain data when recomputing the redeem digest (Fix 1
527
- // on resume). The provider is shared across the driver's lifetime.
498
+ // AV-B.2 (resume): the driver reconstructs TxLock via this provider when
499
+ // recomputing the redeem digest. Shared across the driver's lifetime.
528
500
  const blockchain = await this.platform.createBlockchainProvider(network);
529
501
  const result = await coreResumeAtomicSwap({
530
502
  api: this.api,
@@ -544,13 +516,10 @@ export class AtomicFlow {
544
516
  saveProtocolSnapshot: this.platform.saveProtocolSnapshot,
545
517
  loadProtocolSnapshot: this.platform.loadProtocolSnapshot,
546
518
  });
547
- // If the driver already reached a terminal phase via mapCoreProgress
548
- // (sweep complete, refunded, cancelled, failed, punished), the post-driver
549
- // server re-check is meaningless the server has no scanner for the
550
- // on-chain XMR sweep, so it still reports requiredAction=sweep /
551
- // status=sending right after the client broadcast its sweep tx. Treating
552
- // that as actionable triggers a phantom second executeSweep that emits a
553
- // spurious `completed → sweeping` transition.
519
+ // Skip the server re-check if mapCoreProgress already emitted terminal:
520
+ // the server has no on-chain XMR scanner so it still reports
521
+ // requiredAction=sweep right after our broadcast, which would trigger a
522
+ // phantom second executeSweep and a spurious completed -> sweeping flicker.
554
523
  if (this.hasReachedTerminal)
555
524
  return;
556
525
  let finalStatus = 'completed';
@@ -574,11 +543,9 @@ export class AtomicFlow {
574
543
  this.emitTerminal(result.swapId, finalStatus, undefined);
575
544
  return;
576
545
  }
577
- // Non-terminal status with no immediately-actionable requiredAction
578
- // (e.g., server is still broadcasting TxCancel, or waiting for cancel
579
- // confirmation). Sidecar handles TxCancel automatically; the client just
580
- // needs to watch for the requiredAction to flip to 'refund' (or the
581
- // swap to reach terminal). pollUntilTerminal does both.
546
+ // Non-terminal with no actionable requiredAction (e.g. server still
547
+ // broadcasting TxCancel). Sidecar handles cancel; we wait for the
548
+ // action to flip to 'refund' or the swap to reach terminal.
582
549
  this.setFlowContext({
583
550
  extra: { text: requiredAction?.message ?? 'Waiting for server...', type: 'message' },
584
551
  });
@@ -596,6 +563,9 @@ export class AtomicFlow {
596
563
  this.setFlowContext({ swapNumber: p.swapNumber });
597
564
  if (p.verification)
598
565
  this.setFlowContext({ verification: p.verification });
566
+ if (SWAP_STATUS_STAGES.has(p.stage)) {
567
+ this.lastSeenStatus = p.stage;
568
+ }
599
569
  switch (p.stage) {
600
570
  case 'keygen':
601
571
  case 'keystore_saved':
@@ -671,10 +641,9 @@ export class AtomicFlow {
671
641
  phase: 'completed',
672
642
  snapshot: this.flowCtx,
673
643
  outputTxHash: p.txHash ?? null,
674
- // Atomic swaps have no slippage — the buyer receives exactly the
675
- // negotiated rate × deposit amount. Default to the snapshot's
676
- // expectedOut so the receipt shows the actual amount the user got
677
- // even when the in-flight progress event doesn't carry it.
644
+ // Atomic swaps have no slippage; buyer receives exactly rate * deposit.
645
+ // Fall back to expectedOut so the receipt shows the right number even
646
+ // when the progress event doesn't carry it.
678
647
  actualOut: this.flowCtx?.expectedOut ?? '',
679
648
  durationSec: null,
680
649
  });
@@ -708,9 +677,8 @@ export class AtomicFlow {
708
677
  });
709
678
  break;
710
679
  case 'cancelling':
711
- // Intermediate: BTC TxCancel is in flight, the refund will follow.
712
- // Stay in a watching phase so the driver keeps polling until the row
713
- // settles in `refunded` (or `failed` if the refund never lands).
680
+ // TxCancel in flight; refund follows. Stay watching until the row
681
+ // settles in 'refunded' (or 'failed' if the refund never lands).
714
682
  this.setFlowContext({ extra: { text: p.message, type: 'warning' } });
715
683
  this.transition({
716
684
  phase: 'creating-swap',
@@ -720,11 +688,8 @@ export class AtomicFlow {
720
688
  break;
721
689
  case 'withheld':
722
690
  case 'expired':
723
- // Terminal: the deposit window closed (`expired`) or the maker
724
- // refused to release funds (`withheld`). Both are user-visible
725
- // terminal statuses in `TerminalStatus`. Emit a `failed` phase so
726
- // poll consumers (engine driver, TUI exec state) observe a terminal
727
- // transition and resolve.
691
+ // Both are terminal in TerminalStatus. Emit 'failed' so poll
692
+ // consumers see a terminal transition and resolve.
728
693
  this.transition({
729
694
  phase: 'failed',
730
695
  snapshot: this.flowCtx,
@@ -733,12 +698,9 @@ export class AtomicFlow {
733
698
  break;
734
699
  case 'punished': {
735
700
  // Not terminal. Alice published TxPunish (Bob missed the refund
736
- // window), but the sidecar autonomously runs
737
- // `cooperative_xmr_redeem_after_punish` to recover s_a once Alice
738
- // cooperates, the server flips `requiredAction.type` to `sweep` and
739
- // the driver finishes the swap with an XMR sweep that lands the row
740
- // in `completed`. Stay in a watching phase so `drive.ts`'s existing
741
- // sweep branch can pick up the action transition.
701
+ // window), but the sidecar runs cooperative_xmr_redeem_after_punish
702
+ // to recover s_a; the server then flips requiredAction to 'sweep'
703
+ // and drive.ts finishes via the sweep branch.
742
704
  const reason = p.message ||
743
705
  'BTC punished — recovering XMR via cooperative_xmr_redeem_after_punish...';
744
706
  this.setFlowContext({ extra: { text: reason, type: 'warning' } });
@@ -836,6 +798,7 @@ export class AtomicFlow {
836
798
  receiveAddress: this.keystore.swap.receiveAddress,
837
799
  expectedSAMonero: pp.S_a_monero,
838
800
  monerodNodes: this.config.monerodNodes,
801
+ signal: this.signal,
839
802
  onProgress: (stage) => {
840
803
  const sweepStep = stage.includes('key') ? 'key-images'
841
804
  : stage.includes('submit') || stage.includes('broadcast') ? 'broadcasting'
@@ -1052,12 +1015,10 @@ export class AtomicFlow {
1052
1015
  }
1053
1016
  return '';
1054
1017
  }
1055
- /**
1056
- * Read protocol params from the server response; fall back to the platform
1057
- * adapter's optional write-through cache when the server didn't return the
1058
- * refund encsig. On success from the server, populate the cache so later
1059
- * refunds survive a briefly-unreachable backend.
1060
- */
1018
+ // Server response first; fall back to the platform adapter's optional
1019
+ // write-through cache when the server omitted the refund encsig. On a
1020
+ // good server response, prime the cache so later refunds survive a brief
1021
+ // backend outage.
1061
1022
  async resolveProtocolParams(swapId, detail) {
1062
1023
  const fromServer = extractProtocolData(detail).params;
1063
1024
  if (fromServer && hasRefundEscapeHatch(fromServer)) {
@@ -1109,17 +1070,14 @@ export class AtomicFlow {
1109
1070
  this.emitTerminal(swapId, detail.status, detail);
1110
1071
  return;
1111
1072
  }
1112
- // Opportunistically prime the protocol cache while the server is
1113
- // reachable. The refund path will use this cache if the server is
1114
- // briefly unreachable later.
1073
+ // Prime the protocol cache while the server is up; the refund path
1074
+ // falls back to it if the server goes down later.
1115
1075
  const polledParams = extractProtocolData(detail).params;
1116
1076
  if (polledParams?.tx_full_refund_encsig) {
1117
1077
  await this.cacheProtocolParams(swapId, polledParams);
1118
1078
  }
1119
- // Server flipped the required action to 'refund' TxCancel has
1120
- // confirmed on-chain and Bob's refund window is open. Auto-trigger
1121
- // the client-side refund so we don't drift toward the punish
1122
- // deadline while idly polling.
1079
+ // 'refund' flip means TxCancel confirmed and the refund window is
1080
+ // open. Auto-trigger so we don't drift toward the punish deadline.
1123
1081
  const action = detail.requiredAction ?? null;
1124
1082
  if (action?.type === 'refund') {
1125
1083
  this.logger.info({ swapId, blocksRemaining: action.blocksRemaining ?? null }, 'Required action flipped to refund — auto-triggering client-side refund');
@@ -1170,17 +1128,29 @@ export class AtomicFlow {
1170
1128
  throw new SwapCancelledError();
1171
1129
  }
1172
1130
  handleError(err) {
1173
- if (err instanceof SwapCancelledError || this.signal.aborted) {
1174
- this.logger.info({ swapId: this.flowCtx?.swapId ?? null }, 'AtomicFlow cancelled');
1131
+ const route = routeError(err, this.signal.aborted, this.lastSeenStatus);
1132
+ const swapId = this.flowCtx?.swapId ?? null;
1133
+ if (route.kind === 'cancelled') {
1134
+ this.logger.info({ swapId }, 'AtomicFlow cancelled');
1175
1135
  this.transition({ phase: 'cancelled', snapshot: this.flowCtx, swapId: null, txCancelTxid: null });
1176
1136
  return;
1177
1137
  }
1178
- const message = err instanceof Error ? err.message : String(err);
1179
- this.logger.error({ swapId: this.flowCtx?.swapId ?? null, error: message }, 'AtomicFlow error');
1180
- this.setFlowContext({ extra: { text: message, type: 'error' } });
1138
+ this.logger.error({ swapId, error: route.message, kind: route.kind }, 'AtomicFlow error');
1139
+ this.setFlowContext({ extra: { text: route.message, type: 'error' } });
1140
+ if (route.kind === 'stalled') {
1141
+ this.transition({
1142
+ phase: 'stalled',
1143
+ snapshot: this.flowCtx,
1144
+ error: route.message,
1145
+ swapId,
1146
+ keystoreId: this.keystoreId.length > 0 ? this.keystoreId : null,
1147
+ });
1148
+ return;
1149
+ }
1181
1150
  this.transition({
1182
- phase: 'failed', snapshot: this.flowCtx,
1183
- error: message,
1151
+ phase: 'failed',
1152
+ snapshot: this.flowCtx,
1153
+ error: route.message,
1184
1154
  });
1185
1155
  }
1186
1156
  getCurrentAwaitingActionState() {