@miradexio/client 0.1.0

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 (405) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +405 -0
  3. package/dist/address/base58.d.ts +9 -0
  4. package/dist/address/base58.d.ts.map +1 -0
  5. package/dist/address/base58.js +33 -0
  6. package/dist/address/base58.js.map +1 -0
  7. package/dist/address/bech32.d.ts +13 -0
  8. package/dist/address/bech32.d.ts.map +1 -0
  9. package/dist/address/bech32.js +41 -0
  10. package/dist/address/bech32.js.map +1 -0
  11. package/dist/address/evm.d.ts +5 -0
  12. package/dist/address/evm.d.ts.map +1 -0
  13. package/dist/address/evm.js +27 -0
  14. package/dist/address/evm.js.map +1 -0
  15. package/dist/address/index.d.ts +15 -0
  16. package/dist/address/index.d.ts.map +1 -0
  17. package/dist/address/index.js +134 -0
  18. package/dist/address/index.js.map +1 -0
  19. package/dist/address/monero.d.ts +15 -0
  20. package/dist/address/monero.d.ts.map +1 -0
  21. package/dist/address/monero.js +30 -0
  22. package/dist/address/monero.js.map +1 -0
  23. package/dist/address/polkadot.d.ts +10 -0
  24. package/dist/address/polkadot.d.ts.map +1 -0
  25. package/dist/address/polkadot.js +36 -0
  26. package/dist/address/polkadot.js.map +1 -0
  27. package/dist/address/solana.d.ts +5 -0
  28. package/dist/address/solana.d.ts.map +1 -0
  29. package/dist/address/solana.js +17 -0
  30. package/dist/address/solana.js.map +1 -0
  31. package/dist/address/ton.d.ts +11 -0
  32. package/dist/address/ton.d.ts.map +1 -0
  33. package/dist/address/ton.js +28 -0
  34. package/dist/address/ton.js.map +1 -0
  35. package/dist/api/index.d.ts +80 -0
  36. package/dist/api/index.d.ts.map +1 -0
  37. package/dist/api/index.js +213 -0
  38. package/dist/api/index.js.map +1 -0
  39. package/dist/atomic-swap/drive.d.ts +22 -0
  40. package/dist/atomic-swap/drive.d.ts.map +1 -0
  41. package/dist/atomic-swap/drive.js +713 -0
  42. package/dist/atomic-swap/drive.js.map +1 -0
  43. package/dist/atomic-swap/extract.d.ts +46 -0
  44. package/dist/atomic-swap/extract.d.ts.map +1 -0
  45. package/dist/atomic-swap/extract.js +55 -0
  46. package/dist/atomic-swap/extract.js.map +1 -0
  47. package/dist/atomic-swap/index.d.ts +15 -0
  48. package/dist/atomic-swap/index.d.ts.map +1 -0
  49. package/dist/atomic-swap/index.js +13 -0
  50. package/dist/atomic-swap/index.js.map +1 -0
  51. package/dist/atomic-swap/monero-sweep/errors.d.ts +2 -0
  52. package/dist/atomic-swap/monero-sweep/errors.d.ts.map +1 -0
  53. package/dist/atomic-swap/monero-sweep/errors.js +43 -0
  54. package/dist/atomic-swap/monero-sweep/errors.js.map +1 -0
  55. package/dist/atomic-swap/monero-sweep/index.d.ts +33 -0
  56. package/dist/atomic-swap/monero-sweep/index.d.ts.map +1 -0
  57. package/dist/atomic-swap/monero-sweep/index.js +415 -0
  58. package/dist/atomic-swap/monero-sweep/index.js.map +1 -0
  59. package/dist/atomic-swap/monero-sweep/ring-select.d.ts +12 -0
  60. package/dist/atomic-swap/monero-sweep/ring-select.d.ts.map +1 -0
  61. package/dist/atomic-swap/monero-sweep/ring-select.js +61 -0
  62. package/dist/atomic-swap/monero-sweep/ring-select.js.map +1 -0
  63. package/dist/atomic-swap/presign.d.ts +101 -0
  64. package/dist/atomic-swap/presign.d.ts.map +1 -0
  65. package/dist/atomic-swap/presign.js +460 -0
  66. package/dist/atomic-swap/presign.js.map +1 -0
  67. package/dist/atomic-swap/refund.d.ts +72 -0
  68. package/dist/atomic-swap/refund.d.ts.map +1 -0
  69. package/dist/atomic-swap/refund.js +224 -0
  70. package/dist/atomic-swap/refund.js.map +1 -0
  71. package/dist/atomic-swap/run.d.ts +27 -0
  72. package/dist/atomic-swap/run.d.ts.map +1 -0
  73. package/dist/atomic-swap/run.js +282 -0
  74. package/dist/atomic-swap/run.js.map +1 -0
  75. package/dist/atomic-swap/snapshot.d.ts +111 -0
  76. package/dist/atomic-swap/snapshot.d.ts.map +1 -0
  77. package/dist/atomic-swap/snapshot.js +69 -0
  78. package/dist/atomic-swap/snapshot.js.map +1 -0
  79. package/dist/atomic-swap/submit-encsig.d.ts +10 -0
  80. package/dist/atomic-swap/submit-encsig.d.ts.map +1 -0
  81. package/dist/atomic-swap/submit-encsig.js +56 -0
  82. package/dist/atomic-swap/submit-encsig.js.map +1 -0
  83. package/dist/atomic-swap/types.d.ts +168 -0
  84. package/dist/atomic-swap/types.d.ts.map +1 -0
  85. package/dist/atomic-swap/types.js +5 -0
  86. package/dist/atomic-swap/types.js.map +1 -0
  87. package/dist/blockchain/quorum-provider.d.ts +25 -0
  88. package/dist/blockchain/quorum-provider.d.ts.map +1 -0
  89. package/dist/blockchain/quorum-provider.js +144 -0
  90. package/dist/blockchain/quorum-provider.js.map +1 -0
  91. package/dist/cooperative-redeem.d.ts +23 -0
  92. package/dist/cooperative-redeem.d.ts.map +1 -0
  93. package/dist/cooperative-redeem.js +40 -0
  94. package/dist/cooperative-redeem.js.map +1 -0
  95. package/dist/engine/blockchain-querier.d.ts +34 -0
  96. package/dist/engine/blockchain-querier.d.ts.map +1 -0
  97. package/dist/engine/blockchain-querier.js +2 -0
  98. package/dist/engine/blockchain-querier.js.map +1 -0
  99. package/dist/engine/engine-state.d.ts +20 -0
  100. package/dist/engine/engine-state.d.ts.map +1 -0
  101. package/dist/engine/engine-state.js +9 -0
  102. package/dist/engine/engine-state.js.map +1 -0
  103. package/dist/engine/flow-context.d.ts +494 -0
  104. package/dist/engine/flow-context.d.ts.map +1 -0
  105. package/dist/engine/flow-context.js +147 -0
  106. package/dist/engine/flow-context.js.map +1 -0
  107. package/dist/engine/flows/atomic-flow-state.d.ts +124 -0
  108. package/dist/engine/flows/atomic-flow-state.d.ts.map +1 -0
  109. package/dist/engine/flows/atomic-flow-state.js +2 -0
  110. package/dist/engine/flows/atomic-flow-state.js.map +1 -0
  111. package/dist/engine/flows/atomic-flow.d.ts +88 -0
  112. package/dist/engine/flows/atomic-flow.d.ts.map +1 -0
  113. package/dist/engine/flows/atomic-flow.js +1192 -0
  114. package/dist/engine/flows/atomic-flow.js.map +1 -0
  115. package/dist/engine/flows/history-flow-state.d.ts +19 -0
  116. package/dist/engine/flows/history-flow-state.d.ts.map +1 -0
  117. package/dist/engine/flows/history-flow-state.js +2 -0
  118. package/dist/engine/flows/history-flow-state.js.map +1 -0
  119. package/dist/engine/flows/providers-flow-state.d.ts +14 -0
  120. package/dist/engine/flows/providers-flow-state.d.ts.map +1 -0
  121. package/dist/engine/flows/providers-flow-state.js +2 -0
  122. package/dist/engine/flows/providers-flow-state.js.map +1 -0
  123. package/dist/engine/flows/quote-flow-state.d.ts +20 -0
  124. package/dist/engine/flows/quote-flow-state.d.ts.map +1 -0
  125. package/dist/engine/flows/quote-flow-state.js +2 -0
  126. package/dist/engine/flows/quote-flow-state.js.map +1 -0
  127. package/dist/engine/flows/swap-flow-state.d.ts +155 -0
  128. package/dist/engine/flows/swap-flow-state.d.ts.map +1 -0
  129. package/dist/engine/flows/swap-flow-state.js +2 -0
  130. package/dist/engine/flows/swap-flow-state.js.map +1 -0
  131. package/dist/engine/flows/swap-flow.d.ts +81 -0
  132. package/dist/engine/flows/swap-flow.d.ts.map +1 -0
  133. package/dist/engine/flows/swap-flow.js +720 -0
  134. package/dist/engine/flows/swap-flow.js.map +1 -0
  135. package/dist/engine/flows/tokens-flow-state.d.ts +16 -0
  136. package/dist/engine/flows/tokens-flow-state.d.ts.map +1 -0
  137. package/dist/engine/flows/tokens-flow-state.js +2 -0
  138. package/dist/engine/flows/tokens-flow-state.js.map +1 -0
  139. package/dist/engine/miradex-engine.d.ts +152 -0
  140. package/dist/engine/miradex-engine.d.ts.map +1 -0
  141. package/dist/engine/miradex-engine.js +278 -0
  142. package/dist/engine/miradex-engine.js.map +1 -0
  143. package/dist/engine/pipeline.d.ts +27 -0
  144. package/dist/engine/pipeline.d.ts.map +1 -0
  145. package/dist/engine/pipeline.js +166 -0
  146. package/dist/engine/pipeline.js.map +1 -0
  147. package/dist/engine/platform.d.ts +220 -0
  148. package/dist/engine/platform.d.ts.map +1 -0
  149. package/dist/engine/platform.js +2 -0
  150. package/dist/engine/platform.js.map +1 -0
  151. package/dist/index.d.ts +85 -0
  152. package/dist/index.d.ts.map +1 -0
  153. package/dist/index.js +62 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/interfaces/blockchain.d.ts +33 -0
  156. package/dist/interfaces/blockchain.d.ts.map +1 -0
  157. package/dist/interfaces/blockchain.js +2 -0
  158. package/dist/interfaces/blockchain.js.map +1 -0
  159. package/dist/interfaces/logger.d.ts +14 -0
  160. package/dist/interfaces/logger.d.ts.map +1 -0
  161. package/dist/interfaces/logger.js +7 -0
  162. package/dist/interfaces/logger.js.map +1 -0
  163. package/dist/lib/bitcoin/deposit-watcher.d.ts +66 -0
  164. package/dist/lib/bitcoin/deposit-watcher.d.ts.map +1 -0
  165. package/dist/lib/bitcoin/deposit-watcher.js +218 -0
  166. package/dist/lib/bitcoin/deposit-watcher.js.map +1 -0
  167. package/dist/lib/bitcoin/script-hash.d.ts +8 -0
  168. package/dist/lib/bitcoin/script-hash.d.ts.map +1 -0
  169. package/dist/lib/bitcoin/script-hash.js +29 -0
  170. package/dist/lib/bitcoin/script-hash.js.map +1 -0
  171. package/dist/lib/bitcoin/sweep.d.ts +56 -0
  172. package/dist/lib/bitcoin/sweep.d.ts.map +1 -0
  173. package/dist/lib/bitcoin/sweep.js +185 -0
  174. package/dist/lib/bitcoin/sweep.js.map +1 -0
  175. package/dist/lib/bitcoin/tx-verify.d.ts +43 -0
  176. package/dist/lib/bitcoin/tx-verify.d.ts.map +1 -0
  177. package/dist/lib/bitcoin/tx-verify.js +202 -0
  178. package/dist/lib/bitcoin/tx-verify.js.map +1 -0
  179. package/dist/lib/bitcoin/wallet.d.ts +71 -0
  180. package/dist/lib/bitcoin/wallet.d.ts.map +1 -0
  181. package/dist/lib/bitcoin/wallet.js +141 -0
  182. package/dist/lib/bitcoin/wallet.js.map +1 -0
  183. package/dist/lib/crypto/bytes.d.ts +21 -0
  184. package/dist/lib/crypto/bytes.d.ts.map +1 -0
  185. package/dist/lib/crypto/bytes.js +39 -0
  186. package/dist/lib/crypto/bytes.js.map +1 -0
  187. package/dist/lib/crypto/errors.d.ts +12 -0
  188. package/dist/lib/crypto/errors.d.ts.map +1 -0
  189. package/dist/lib/crypto/errors.js +16 -0
  190. package/dist/lib/crypto/errors.js.map +1 -0
  191. package/dist/lib/crypto/keygen.d.ts +19 -0
  192. package/dist/lib/crypto/keygen.d.ts.map +1 -0
  193. package/dist/lib/crypto/keygen.js +24 -0
  194. package/dist/lib/crypto/keygen.js.map +1 -0
  195. package/dist/lib/crypto/libp2p-identity.d.ts +25 -0
  196. package/dist/lib/crypto/libp2p-identity.d.ts.map +1 -0
  197. package/dist/lib/crypto/libp2p-identity.js +80 -0
  198. package/dist/lib/crypto/libp2p-identity.js.map +1 -0
  199. package/dist/lib/crypto/mnemonic.d.ts +28 -0
  200. package/dist/lib/crypto/mnemonic.d.ts.map +1 -0
  201. package/dist/lib/crypto/mnemonic.js +97 -0
  202. package/dist/lib/crypto/mnemonic.js.map +1 -0
  203. package/dist/lib/crypto/platform.d.ts +10 -0
  204. package/dist/lib/crypto/platform.d.ts.map +1 -0
  205. package/dist/lib/crypto/platform.js +38 -0
  206. package/dist/lib/crypto/platform.js.map +1 -0
  207. package/dist/lib/crypto/scalars.d.ts +33 -0
  208. package/dist/lib/crypto/scalars.d.ts.map +1 -0
  209. package/dist/lib/crypto/scalars.js +81 -0
  210. package/dist/lib/crypto/scalars.js.map +1 -0
  211. package/dist/lib/crypto/types.d.ts +24 -0
  212. package/dist/lib/crypto/types.d.ts.map +1 -0
  213. package/dist/lib/crypto/types.js +2 -0
  214. package/dist/lib/crypto/types.js.map +1 -0
  215. package/dist/lib/crypto/wasm.d.ts +51 -0
  216. package/dist/lib/crypto/wasm.d.ts.map +1 -0
  217. package/dist/lib/crypto/wasm.js +192 -0
  218. package/dist/lib/crypto/wasm.js.map +1 -0
  219. package/dist/lib/default-config.d.ts +140 -0
  220. package/dist/lib/default-config.d.ts.map +1 -0
  221. package/dist/lib/default-config.js +239 -0
  222. package/dist/lib/default-config.js.map +1 -0
  223. package/dist/lib/delay.d.ts +6 -0
  224. package/dist/lib/delay.d.ts.map +1 -0
  225. package/dist/lib/delay.js +20 -0
  226. package/dist/lib/delay.js.map +1 -0
  227. package/dist/lib/errors.d.ts +90 -0
  228. package/dist/lib/errors.d.ts.map +1 -0
  229. package/dist/lib/errors.js +129 -0
  230. package/dist/lib/errors.js.map +1 -0
  231. package/dist/lib/format.d.ts +7 -0
  232. package/dist/lib/format.d.ts.map +1 -0
  233. package/dist/lib/format.js +43 -0
  234. package/dist/lib/format.js.map +1 -0
  235. package/dist/lib/keystore.d.ts +85 -0
  236. package/dist/lib/keystore.d.ts.map +1 -0
  237. package/dist/lib/keystore.js +105 -0
  238. package/dist/lib/keystore.js.map +1 -0
  239. package/dist/lib/monero/output-scanner.d.ts +53 -0
  240. package/dist/lib/monero/output-scanner.d.ts.map +1 -0
  241. package/dist/lib/monero/output-scanner.js +180 -0
  242. package/dist/lib/monero/output-scanner.js.map +1 -0
  243. package/dist/lib/monero/rpc.d.ts +131 -0
  244. package/dist/lib/monero/rpc.d.ts.map +1 -0
  245. package/dist/lib/monero/rpc.js +267 -0
  246. package/dist/lib/monero/rpc.js.map +1 -0
  247. package/dist/lib/monero/verify-lock.d.ts +50 -0
  248. package/dist/lib/monero/verify-lock.d.ts.map +1 -0
  249. package/dist/lib/monero/verify-lock.js +161 -0
  250. package/dist/lib/monero/verify-lock.js.map +1 -0
  251. package/dist/lib/monero/verify-sweep.d.ts +59 -0
  252. package/dist/lib/monero/verify-sweep.d.ts.map +1 -0
  253. package/dist/lib/monero/verify-sweep.js +82 -0
  254. package/dist/lib/monero/verify-sweep.js.map +1 -0
  255. package/dist/lib/monero/wasm.d.ts +19 -0
  256. package/dist/lib/monero/wasm.d.ts.map +1 -0
  257. package/dist/lib/monero/wasm.js +24 -0
  258. package/dist/lib/monero/wasm.js.map +1 -0
  259. package/dist/lib/pow-solver.d.ts +4 -0
  260. package/dist/lib/pow-solver.d.ts.map +1 -0
  261. package/dist/lib/pow-solver.js +37 -0
  262. package/dist/lib/pow-solver.js.map +1 -0
  263. package/dist/lib/retry.d.ts +86 -0
  264. package/dist/lib/retry.d.ts.map +1 -0
  265. package/dist/lib/retry.js +104 -0
  266. package/dist/lib/retry.js.map +1 -0
  267. package/dist/portable.d.ts +23 -0
  268. package/dist/portable.d.ts.map +1 -0
  269. package/dist/portable.js +13 -0
  270. package/dist/portable.js.map +1 -0
  271. package/dist/quote-binding.d.ts +31 -0
  272. package/dist/quote-binding.d.ts.map +1 -0
  273. package/dist/quote-binding.js +40 -0
  274. package/dist/quote-binding.js.map +1 -0
  275. package/dist/swap-executor.d.ts +51 -0
  276. package/dist/swap-executor.d.ts.map +1 -0
  277. package/dist/swap-executor.js +138 -0
  278. package/dist/swap-executor.js.map +1 -0
  279. package/dist/types/api.d.ts +34 -0
  280. package/dist/types/api.d.ts.map +1 -0
  281. package/dist/types/api.js +18 -0
  282. package/dist/types/api.js.map +1 -0
  283. package/dist/types/errors.d.ts +94 -0
  284. package/dist/types/errors.d.ts.map +1 -0
  285. package/dist/types/errors.js +93 -0
  286. package/dist/types/errors.js.map +1 -0
  287. package/dist/types/index.d.ts +8 -0
  288. package/dist/types/index.d.ts.map +1 -0
  289. package/dist/types/index.js +10 -0
  290. package/dist/types/index.js.map +1 -0
  291. package/dist/types/keys.d.ts +33 -0
  292. package/dist/types/keys.d.ts.map +1 -0
  293. package/dist/types/keys.js +2 -0
  294. package/dist/types/keys.js.map +1 -0
  295. package/dist/types/protocol.d.ts +93 -0
  296. package/dist/types/protocol.d.ts.map +1 -0
  297. package/dist/types/protocol.js +18 -0
  298. package/dist/types/protocol.js.map +1 -0
  299. package/dist/types/status.d.ts +3 -0
  300. package/dist/types/status.d.ts.map +1 -0
  301. package/dist/types/status.js +23 -0
  302. package/dist/types/status.js.map +1 -0
  303. package/dist/types/verification.d.ts +49 -0
  304. package/dist/types/verification.d.ts.map +1 -0
  305. package/dist/types/verification.js +34 -0
  306. package/dist/types/verification.js.map +1 -0
  307. package/dist/verification/atomic-swap.d.ts +9 -0
  308. package/dist/verification/atomic-swap.d.ts.map +1 -0
  309. package/dist/verification/atomic-swap.js +22 -0
  310. package/dist/verification/atomic-swap.js.map +1 -0
  311. package/dist/verification/chainflip-networks.d.ts +46 -0
  312. package/dist/verification/chainflip-networks.d.ts.map +1 -0
  313. package/dist/verification/chainflip-networks.js +24 -0
  314. package/dist/verification/chainflip-networks.js.map +1 -0
  315. package/dist/verification/chainflip.d.ts +61 -0
  316. package/dist/verification/chainflip.d.ts.map +1 -0
  317. package/dist/verification/chainflip.js +377 -0
  318. package/dist/verification/chainflip.js.map +1 -0
  319. package/dist/verification/constants.d.ts +52 -0
  320. package/dist/verification/constants.d.ts.map +1 -0
  321. package/dist/verification/constants.js +54 -0
  322. package/dist/verification/constants.js.map +1 -0
  323. package/dist/verification/index.d.ts +71 -0
  324. package/dist/verification/index.d.ts.map +1 -0
  325. package/dist/verification/index.js +91 -0
  326. package/dist/verification/index.js.map +1 -0
  327. package/dist/verification/memo.d.ts +27 -0
  328. package/dist/verification/memo.d.ts.map +1 -0
  329. package/dist/verification/memo.js +52 -0
  330. package/dist/verification/memo.js.map +1 -0
  331. package/dist/verification/near-intents.d.ts +91 -0
  332. package/dist/verification/near-intents.d.ts.map +1 -0
  333. package/dist/verification/near-intents.js +213 -0
  334. package/dist/verification/near-intents.js.map +1 -0
  335. package/dist/verification/rate-oracle.d.ts +32 -0
  336. package/dist/verification/rate-oracle.d.ts.map +1 -0
  337. package/dist/verification/rate-oracle.js +43 -0
  338. package/dist/verification/rate-oracle.js.map +1 -0
  339. package/dist/verification/shared.d.ts +20 -0
  340. package/dist/verification/shared.d.ts.map +1 -0
  341. package/dist/verification/shared.js +25 -0
  342. package/dist/verification/shared.js.map +1 -0
  343. package/dist/verification/thorchain-networks.d.ts +35 -0
  344. package/dist/verification/thorchain-networks.d.ts.map +1 -0
  345. package/dist/verification/thorchain-networks.js +35 -0
  346. package/dist/verification/thorchain-networks.js.map +1 -0
  347. package/dist/verification/thorchain.d.ts +55 -0
  348. package/dist/verification/thorchain.d.ts.map +1 -0
  349. package/dist/verification/thorchain.js +232 -0
  350. package/dist/verification/thorchain.js.map +1 -0
  351. package/dist/wasm-pins.d.ts +4 -0
  352. package/dist/wasm-pins.d.ts.map +1 -0
  353. package/dist/wasm-pins.js +6 -0
  354. package/dist/wasm-pins.js.map +1 -0
  355. package/dist/wire/chainflip.zod.d.ts +144 -0
  356. package/dist/wire/chainflip.zod.d.ts.map +1 -0
  357. package/dist/wire/chainflip.zod.js +33 -0
  358. package/dist/wire/chainflip.zod.js.map +1 -0
  359. package/dist/wire/near-intents.zod.d.ts +376 -0
  360. package/dist/wire/near-intents.zod.d.ts.map +1 -0
  361. package/dist/wire/near-intents.zod.js +101 -0
  362. package/dist/wire/near-intents.zod.js.map +1 -0
  363. package/dist/wire/server/action.zod.d.ts +1119 -0
  364. package/dist/wire/server/action.zod.d.ts.map +1 -0
  365. package/dist/wire/server/action.zod.js +173 -0
  366. package/dist/wire/server/action.zod.js.map +1 -0
  367. package/dist/wire/server/common.zod.d.ts +62 -0
  368. package/dist/wire/server/common.zod.d.ts.map +1 -0
  369. package/dist/wire/server/common.zod.js +43 -0
  370. package/dist/wire/server/common.zod.js.map +1 -0
  371. package/dist/wire/server/index.d.ts +8 -0
  372. package/dist/wire/server/index.d.ts.map +1 -0
  373. package/dist/wire/server/index.js +8 -0
  374. package/dist/wire/server/index.js.map +1 -0
  375. package/dist/wire/server/pow.zod.d.ts +45 -0
  376. package/dist/wire/server/pow.zod.d.ts.map +1 -0
  377. package/dist/wire/server/pow.zod.js +18 -0
  378. package/dist/wire/server/pow.zod.js.map +1 -0
  379. package/dist/wire/server/quotes.zod.d.ts +694 -0
  380. package/dist/wire/server/quotes.zod.d.ts.map +1 -0
  381. package/dist/wire/server/quotes.zod.js +103 -0
  382. package/dist/wire/server/quotes.zod.js.map +1 -0
  383. package/dist/wire/server/swap.zod.d.ts +1981 -0
  384. package/dist/wire/server/swap.zod.d.ts.map +1 -0
  385. package/dist/wire/server/swap.zod.js +270 -0
  386. package/dist/wire/server/swap.zod.js.map +1 -0
  387. package/dist/wire/server/tokens.zod.d.ts +93 -0
  388. package/dist/wire/server/tokens.zod.d.ts.map +1 -0
  389. package/dist/wire/server/tokens.zod.js +28 -0
  390. package/dist/wire/server/tokens.zod.js.map +1 -0
  391. package/dist/wire/server/verify.zod.d.ts +30 -0
  392. package/dist/wire/server/verify.zod.d.ts.map +1 -0
  393. package/dist/wire/server/verify.zod.js +12 -0
  394. package/dist/wire/server/verify.zod.js.map +1 -0
  395. package/dist/wire/thorchain.zod.d.ts +224 -0
  396. package/dist/wire/thorchain.zod.d.ts.map +1 -0
  397. package/dist/wire/thorchain.zod.js +51 -0
  398. package/dist/wire/thorchain.zod.js.map +1 -0
  399. package/package.json +128 -0
  400. package/wasm/miradex-rust/README.md +74 -0
  401. package/wasm/miradex-rust/miradex_rust.d.ts +149 -0
  402. package/wasm/miradex-rust/miradex_rust.js +943 -0
  403. package/wasm/miradex-rust/miradex_rust_bg.wasm +0 -0
  404. package/wasm/miradex-rust/miradex_rust_bg.wasm.d.ts +31 -0
  405. package/wasm/miradex-rust/package.json +24 -0
@@ -0,0 +1,713 @@
1
+ /**
2
+ * Main action loop: polls the server, inspects requiredAction, and performs
3
+ * the appropriate client-side operation. Handles fund, encsig, sweep,
4
+ * sidecar retries, and terminal states in one unified loop.
5
+ */
6
+ import { sha256 } from '@noble/hashes/sha2.js';
7
+ import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';
8
+ // `crypto.randomUUID` is gated to secure contexts in some browser versions —
9
+ // self-hosted miradex-web on plain HTTP (LAN IP, .local, onion) hits
10
+ // "globalThis.crypto.randomUUID is not a function" before any swap code can
11
+ // run. `crypto.getRandomValues` has no such restriction (it's the underlying
12
+ // entropy primitive), so synthesise a v4 UUID from 16 random bytes when the
13
+ // shortcut isn't available.
14
+ function randomUuidV4() {
15
+ const c = globalThis.crypto;
16
+ if (c?.randomUUID)
17
+ return c.randomUUID();
18
+ if (!c?.getRandomValues) {
19
+ throw new Error('Missing crypto entropy source (getRandomValues)');
20
+ }
21
+ const b = new Uint8Array(16);
22
+ c.getRandomValues(b);
23
+ // RFC 4122 §4.4 — set version (4) and variant (10xx) bits.
24
+ b[6] = ((b[6] ?? 0) & 0x0f) | 0x40;
25
+ b[8] = ((b[8] ?? 0) & 0x3f) | 0x80;
26
+ const h = Array.from(b, (n) => n.toString(16).padStart(2, '0')).join('');
27
+ return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
28
+ }
29
+ import { Point } from '@noble/ed25519';
30
+ import { buildUnsignedFundingPsbt, signFundingPsbt } from '../lib/bitcoin/wallet.js';
31
+ import { buildProtocolSnapshot } from './snapshot.js';
32
+ import { computePreSigs, computeRedeemDigest, computeRedeemDigestFromTxHex, deriveLockAddress, } from './presign.js';
33
+ import { sweepMonero } from './monero-sweep/index.js';
34
+ import { verifyXmrLocked } from '../lib/monero/verify-lock.js';
35
+ import { TERMINAL_STATUSES, VerificationError, ProtocolError, } from '../types/index.js';
36
+ import { constantTimeEqualHex } from '../lib/crypto/bytes.js';
37
+ import { encsignDigest, verifyDleqProof, ensureWasm } from '../lib/crypto/wasm.js';
38
+ import { verifyDepositAddress } from '../verification/index.js';
39
+ import { delay } from '../lib/delay.js';
40
+ import { SwapCancelledError } from './types.js';
41
+ import { extractProtocolData } from './extract.js';
42
+ import { FUNDING_POLL_MS, FUNDING_SETTLE_MS, SWEEP_TIMEOUT_MS, MIN_XMR_CONFIRMATIONS as CFG_MIN_XMR_CONFIRMATIONS, } from '../lib/default-config.js';
43
+ const POLL_MS = FUNDING_POLL_MS * 3; // driver polls less often than the UI deposit watcher
44
+ const TIMEOUT_MS = SWEEP_TIMEOUT_MS;
45
+ const FUND_SETTLE_MS = FUNDING_SETTLE_MS;
46
+ const MIN_XMR_CONFIRMATIONS = CFG_MIN_XMR_CONFIRMATIONS;
47
+ const MAX_ENCSIG_FAILURES = 3;
48
+ /**
49
+ * Drive a created swap through every phase until a terminal state. The swap
50
+ * must already exist on the server; callers are `runAtomicSwap` and
51
+ * `resumeAtomicSwap`.
52
+ *
53
+ * @internal Not part of the stable public surface.
54
+ */
55
+ export async function driveSwapToCompletion(options) {
56
+ const { api, swapId, keystoreId, wallet: _wallet, deposit, keystore, network, onProgress, signal, logger: log, blockchain, saveProtocolSnapshot, loadProtocolSnapshot, makerPeerId, makerMultiaddrs, clientVersion, } = options;
57
+ const deadline = Date.now() + TIMEOUT_MS;
58
+ let lastSignedPsbt = '';
59
+ let lastFundedAddress = '';
60
+ let fundedAt = 0;
61
+ let verificationEmitted = false;
62
+ let encsigFailures = 0;
63
+ let aliceDleqVerified = false;
64
+ let xmrLockVerified = false;
65
+ // Bail if the sidecar keeps rejecting /presigs with "no pending PSBT" /
66
+ // "cannot perform presigs" while the swap is still pre-funding. That
67
+ // pattern means the broker entry was consumed (or never armed) and we
68
+ // can't progress without sidecar cooperation. Looping until TIMEOUT_MS
69
+ // burns minutes and starves the failed-receipt restart UX, so cap the
70
+ // retries explicitly.
71
+ let presigsAlreadyDoneStreak = 0;
72
+ const PRESIGS_ALREADY_DONE_MAX = 6;
73
+ log.info({ swapId, network, deadline: new Date(deadline).toISOString() }, '[drive] loop started');
74
+ let lastLoggedAction;
75
+ while (Date.now() < deadline) {
76
+ if (signal?.aborted)
77
+ throw new SwapCancelledError();
78
+ const detail = await api.getSwapDetail(swapId);
79
+ const action = detail.requiredAction?.type;
80
+ const pdx = extractProtocolData(detail);
81
+ if (action !== lastLoggedAction) {
82
+ log.info({ swapId, status: detail.status, action }, '[drive] required-action changed');
83
+ lastLoggedAction = action;
84
+ }
85
+ if (TERMINAL_STATUSES.has(detail.status)) {
86
+ log.info({ swapId, status: detail.status }, '[drive] terminal status reached');
87
+ onProgress({ stage: detail.status, message: `Swap ${detail.status}`, swapId });
88
+ return;
89
+ }
90
+ if (action === 'fund') {
91
+ const pastFunding = detail.status !== 'initializing'
92
+ && detail.status !== 'awaiting_funding'
93
+ && detail.status !== 'pending';
94
+ // "Funding still pending" is now derived from the deposit address being
95
+ // present and the swap being in a pre-deposit state. The legacy
96
+ // top-level `pendingPsbt` field has been absorbed into the typed
97
+ // atomicswap_parameters row (unsigned_lock_psbt) surfaced via
98
+ // protocolData.params.
99
+ const hasPending = !!detail.depositAddress && !pastFunding;
100
+ if (pastFunding && !hasPending && fundedAt > 0 && Date.now() - fundedAt > FUND_SETTLE_MS) {
101
+ await delay(POLL_MS, signal);
102
+ continue;
103
+ }
104
+ if (hasPending && fundedAt > 0)
105
+ fundedAt = 0;
106
+ // Lock address is always the primary deposit address (the scanner
107
+ // overwrites this on every poll with the freshest value from the
108
+ // sidecar; retry-with-new-maker updates it automatically).
109
+ const lockAddress = detail.depositAddress;
110
+ if (lockAddress && lockAddress !== lastFundedAddress) {
111
+ if (!aliceDleqVerified) {
112
+ // V-2: DLEQ verification is mandatory before broadcasting TxLock.
113
+ // The proof binds S_a_bitcoin and S_a_monero to the same scalar; it
114
+ // is the only thing that lets Bob recover s_a_xmr autonomously from
115
+ // an on-chain TxRedeem signature if the sidecar later refuses to
116
+ // hand back s_a. Skipping it (the previous fall-through on null /
117
+ // missing) leaves Bob trusting the sidecar end-to-end for sweep.
118
+ const pp = pdx.params;
119
+ if (!pp?.dleq_proof_s_a) {
120
+ log.debug({ swapId }, 'Alice DLEQ proof not yet available; awaiting protocol params');
121
+ await delay(POLL_MS, signal);
122
+ continue;
123
+ }
124
+ if (!pp.S_a_monero || !pp.S_a_bitcoin) {
125
+ throw new VerificationError('E_DLEQ_PROOF_REQUIRED', 'Alice DLEQ proof was provided but S_a_bitcoin / S_a_monero is missing; refusing to fund without a complete cross-curve binding');
126
+ }
127
+ log.info({ swapId }, 'Verifying Alice DLEQ proof client-side');
128
+ await ensureWasm();
129
+ const dleqValid = verifyDleqProof(pp.S_a_bitcoin, pp.S_a_monero, pp.dleq_proof_s_a);
130
+ if (!dleqValid) {
131
+ log.error({ swapId }, 'Alice DLEQ proof verification failed');
132
+ throw new VerificationError('E_DLEQ_PROOF_INVALID', 'Alice DLEQ proof is invalid; her Bitcoin and Monero keys are not linked, refusing to fund');
133
+ }
134
+ aliceDleqVerified = true;
135
+ }
136
+ if (!verificationEmitted && detail.verification && detail.depositAddress) {
137
+ verificationEmitted = true;
138
+ const vr = await verifyDepositAddress({
139
+ depositAddress: detail.depositAddress,
140
+ verification: detail.verification,
141
+ destAddress: keystore.swap.receiveAddress,
142
+ refundAddress: keystore.swap.refundAddress,
143
+ toToken: 'XMR',
144
+ amount: '',
145
+ // lock_address is the top-level depositAddress; timelock_blocks
146
+ // comes from the typed atomicswap params when present.
147
+ protocol: detail.depositAddress &&
148
+ detail.protocolData?.type === 'atomicswap' &&
149
+ detail.protocolData.params
150
+ ? {
151
+ lock_address: detail.depositAddress,
152
+ timelock_blocks: detail.protocolData.params.cancel_timelock,
153
+ }
154
+ : undefined,
155
+ expectedDestAddress: keystore.swap.receiveAddress,
156
+ });
157
+ onProgress({
158
+ stage: 'signing_psbt',
159
+ message: vr.verified ? 'Contract verified' : 'verification failed',
160
+ swapId,
161
+ verification: vr,
162
+ });
163
+ if (!vr.verified) {
164
+ throw new VerificationError('E_XMR_LOCK_FAILED', 'lock contract verification failed, refusing to sign PSBT');
165
+ }
166
+ }
167
+ const protocolParams = pdx.params;
168
+ if (!protocolParams) {
169
+ // The sidecar populates protocolData.depositAddress and
170
+ // protocolData.protocolParams in separate writes. It's normal for
171
+ // the client to see requiredAction=='fund' + a depositAddress
172
+ // before protocolParams has landed. Wait and re-poll rather than
173
+ // bail — the outer TIMEOUT_MS bounds the total wait.
174
+ log.debug({ swapId }, 'Fund requested but protocolParams not yet populated; waiting');
175
+ onProgress({
176
+ stage: 'signing_psbt',
177
+ message: 'Waiting for protocol params from sidecar',
178
+ swapId,
179
+ });
180
+ await delay(POLL_MS, signal);
181
+ continue;
182
+ }
183
+ // AV-B.1: derive P2WSH from (A, B) locally and reject anything else.
184
+ const derivedLockAddress = deriveLockAddress({
185
+ aHex: protocolParams.A,
186
+ bHex: keystore.keys.B,
187
+ network,
188
+ });
189
+ if (derivedLockAddress !== lockAddress) {
190
+ log.error({ swapId, derivedLockAddress, claimedLockAddress: lockAddress }, 'Lock address derived from (A, B) does not match sidecar');
191
+ throw new VerificationError('E_LOCK_ADDR_MISMATCH', 'derived P2WSH address does not match sidecar, refusing to fund');
192
+ }
193
+ onProgress({
194
+ stage: 'signing_psbt',
195
+ message: `Building lock tx to ${lockAddress.slice(0, 16)}`,
196
+ swapId,
197
+ });
198
+ // Lock amount in sats — derived from the swap's amountIn. The
199
+ // legacy top-level pendingPsbt.amount was a 1:1 synthesis of this.
200
+ const lockAmountSats = detail.amountIn
201
+ ? Math.round(parseFloat(detail.amountIn) * 1e8)
202
+ : undefined;
203
+ const utxoInputs = deposit.utxos ?? [deposit];
204
+ log.info({
205
+ swapId,
206
+ lockAddress,
207
+ lockAmountSats,
208
+ utxoCount: utxoInputs.length,
209
+ totalInputSats: utxoInputs.reduce((sum, u) => sum + u.value, 0),
210
+ }, '[fund] Phase 1 — building unsigned lock PSBT');
211
+ // Three-step lock-tx flow matching the Rust binary's order:
212
+ // 1. Build UNSIGNED PSBT — that's what the sidecar puts on the wire
213
+ // in Message2.
214
+ // 2. Submit /presigs (unsigned PSBT + Bob's pre-sigs). Sidecar drives
215
+ // Message2/3/4 with Alice and returns the encsig in the response.
216
+ // 3. Snapshot to disk, then sign locally and submit /fund. The
217
+ // broadcast only happens after the snapshot exists, so the client
218
+ // can never end up with BTC on-chain and no autonomous-refund
219
+ // material.
220
+ const unsigned = buildUnsignedFundingPsbt(_wallet, utxoInputs, lockAddress, network, lockAmountSats);
221
+ log.info({ swapId, txid: unsigned.txid, vout: unsigned.vout, amountSats: unsigned.amountSats }, '[fund] Phase 1 — unsigned PSBT built');
222
+ const signedPsbt = signFundingPsbt(unsigned.psbtBase64, _wallet, network);
223
+ log.info({ swapId }, '[fund] Phase 1 — PSBT signed locally (held in memory)');
224
+ if (!keystore.keys.b || !keystore.swap.refundAddress) {
225
+ throw new ProtocolError('E_PROTOCOL_PARAMS_MISSING', 'keystore is missing b or refund address; cannot compute pre-sigs');
226
+ }
227
+ const preSigs = computePreSigs({
228
+ bHex: keystore.keys.b,
229
+ signedPsbtBase64: signedPsbt,
230
+ protocolParams,
231
+ refundAddress: keystore.swap.refundAddress,
232
+ network,
233
+ });
234
+ log.info({ swapId }, '[fund] Phase 1 — pre-sigs computed');
235
+ onProgress({ stage: 'funding', message: 'Submitting pre-sigs (unsigned PSBT)', swapId });
236
+ log.info({ swapId }, '[fund] Phase 2 — POST /presigs (unsigned PSBT + pre-sigs → awaiting Message3)');
237
+ // If the sidecar already processed /presigs on a prior attempt (state
238
+ // now past AWAITING_DEPOSIT with the encsig on protocolParams), skip
239
+ // the call — it would 409 "no pending PSBT" because the sidecar is
240
+ // waiting for /fund. Idempotent recovery from a schema-mismatch retry.
241
+ // Either encsig counts: amnesty (Partial-only) swaps never get a
242
+ // tx_full_refund_encsig, so gating on full alone would force a
243
+ // re-attempt of /presigs that the sidecar would reject.
244
+ const alreadyHasEncsig = !!(protocolParams.tx_full_refund_encsig || protocolParams.tx_partial_refund_encsig) &&
245
+ !!pdx.redeemDigestHex;
246
+ let presigsResponse = null;
247
+ if (alreadyHasEncsig) {
248
+ log.info({ swapId }, '[fund] Phase 2 — sidecar already past /presigs (encsig on status); skipping presigs call');
249
+ presigsAlreadyDoneStreak = 0;
250
+ }
251
+ else {
252
+ try {
253
+ presigsResponse = await api.executeAction(swapId, {
254
+ type: 'presigs',
255
+ unsignedPsbt: unsigned.psbtBase64,
256
+ targetAddress: lockAddress,
257
+ preSigs,
258
+ });
259
+ presigsAlreadyDoneStreak = 0;
260
+ }
261
+ catch (err) {
262
+ const msg = err instanceof Error ? err.message : String(err);
263
+ // "No pending PSBT request" means the sidecar already drove past
264
+ // the presigs step. Re-poll to pick up the encsig off status —
265
+ // DO NOT retry /presigs (the sidecar is past that state).
266
+ if (msg.includes('no pending PSBT') || msg.includes('cannot perform presigs')) {
267
+ presigsAlreadyDoneStreak += 1;
268
+ if (presigsAlreadyDoneStreak >= PRESIGS_ALREADY_DONE_MAX) {
269
+ // The sidecar's PsbtBroker entry was consumed (or never
270
+ // armed after a sidecar restart) and the next iteration of
271
+ // /getSwapDetail still doesn't surface the encsig that
272
+ // would let us skip /presigs. Bail to failed so the
273
+ // failed-receipt restart UX takes over instead of
274
+ // burning the rest of TIMEOUT_MS in a tight retry loop.
275
+ throw new ProtocolError('E_PRESIGS_WEDGED', `sidecar rejected /presigs ${presigsAlreadyDoneStreak} times with "${msg}" — swap is wedged (broker entry consumed but encsig never surfaced on /getSwapDetail)`);
276
+ }
277
+ log.warn({
278
+ swapId,
279
+ error: msg,
280
+ streak: presigsAlreadyDoneStreak,
281
+ cap: PRESIGS_ALREADY_DONE_MAX,
282
+ }, '[fund] Phase 2 — /presigs rejected because sidecar is past that step; re-polling for encsig');
283
+ await delay(POLL_MS, signal);
284
+ continue;
285
+ }
286
+ log.warn({ swapId, error: msg }, '[fund] Phase 2 — presigs attempt failed, will retry');
287
+ await delay(POLL_MS, signal);
288
+ continue;
289
+ }
290
+ }
291
+ const encsigData = alreadyHasEncsig
292
+ ? {
293
+ txFullRefundEncsig: protocolParams.tx_full_refund_encsig ?? null,
294
+ txPartialRefundEncsig: protocolParams.tx_partial_refund_encsig ?? null,
295
+ // Resume / replay path: pull from the typed protocolParams that
296
+ // the sidecar mirrored to /getSwapDetail.
297
+ txCancelSig: protocolParams.tx_cancel_sig ?? null,
298
+ txLockTxid: unsigned.txid,
299
+ txLockVout: unsigned.vout,
300
+ txLockAmountSats: String(unsigned.amountSats),
301
+ }
302
+ : extractPresigsEncsig(presigsResponse);
303
+ log.info({
304
+ swapId,
305
+ hasFullEncsig: !!encsigData.txFullRefundEncsig,
306
+ hasPartialEncsig: !!encsigData.txPartialRefundEncsig,
307
+ txLockTxid: encsigData.txLockTxid,
308
+ }, '[fund] Phase 2 — /presigs response received');
309
+ // Refuse only when neither escape hatch is available. The sidecar
310
+ // returns tx_full_refund_encsig for Legacy/Full variants and
311
+ // tx_partial_refund_encsig (with the amnesty triple on protocolParams)
312
+ // for Partial/Full variants. A Partial-only swap legitimately has
313
+ // a null full encsig — its refund path is TxPartialRefund + TxReclaim.
314
+ if (!encsigData.txFullRefundEncsig && !encsigData.txPartialRefundEncsig) {
315
+ throw new ProtocolError('E_ENCSIG_REFUND_MISSING', 'sidecar accepted /presigs but returned no refund encsig (neither tx_full_refund_encsig nor tx_partial_refund_encsig); refusing to fund without a refund escape hatch');
316
+ }
317
+ log.info({ swapId }, '[fund] Phase 3 — writing recovery snapshot before broadcast');
318
+ // V-16 enabling-work: prefer the value the sidecar returned in the
319
+ // /presigs response, fall back to whatever's already on
320
+ // protocolParams (resume path), then null. Persisting it to the
321
+ // snapshot is a no-op for the current sidecar-publishes-cancel flow,
322
+ // but seeds future autonomous-cancel work with everything it needs.
323
+ const aliceTxCancelSig = encsigData.txCancelSig ?? protocolParams.tx_cancel_sig ?? pdx.aliceTxCancelSig ?? null;
324
+ await maybeWriteSnapshot({
325
+ saveProtocolSnapshot,
326
+ loadProtocolSnapshot,
327
+ swapId,
328
+ externalSwapId: detail.swapNumber,
329
+ keystoreId,
330
+ network,
331
+ clientVersion,
332
+ unsignedPsbtBase64: unsigned.psbtBase64,
333
+ lockAddress,
334
+ lockTxid: unsigned.txid || (encsigData.txLockTxid ?? ''),
335
+ lockVout: encsigData.txLockVout ?? unsigned.vout,
336
+ lockAmountSats: encsigData.txLockAmountSats ?? String(unsigned.amountSats),
337
+ protocolParams,
338
+ encsigFull: encsigData.txFullRefundEncsig,
339
+ encsigPartial: encsigData.txPartialRefundEncsig,
340
+ aliceTxCancelSig,
341
+ makerPeerId: pdx.makerPeerId ?? makerPeerId,
342
+ makerMultiaddrs: pdx.makerMultiaddrs ?? makerMultiaddrs,
343
+ xmrVerification: pdx.xmrVerification,
344
+ sidecarStateAtCapture: detail.status,
345
+ log,
346
+ });
347
+ log.info({ swapId }, '[fund] Phase 3 — snapshot persisted');
348
+ onProgress({ stage: 'funding', message: 'Submitting signed PSBT for broadcast', swapId });
349
+ log.info({ swapId }, '[fund] Phase 4 — POST /fund (signed PSBT → broadcast)');
350
+ // Retry /fund locally with backoff on the "broker not yet awaiting"
351
+ // error. This should be rare since the sidecar now pre-arms the
352
+ // broker in /presigs, but flaky networks or a re-entry from resume
353
+ // can still produce a short window. Retrying /fund is cheap; looping
354
+ // back to the top of drive() would rebuild the PSBT with a stale
355
+ // lockAmountSats (pendingPsbt is gone after /presigs) and produce a
356
+ // different txid — the sidecar would then reject it.
357
+ let fundSucceeded = false;
358
+ for (let attempt = 0; attempt < 6 && !fundSucceeded; attempt++) {
359
+ try {
360
+ await api.executeAction(swapId, { type: 'fund', signedPsbt });
361
+ lastFundedAddress = lockAddress;
362
+ lastSignedPsbt = signedPsbt;
363
+ fundedAt = Date.now();
364
+ fundSucceeded = true;
365
+ onProgress({ stage: 'funding', message: 'Broadcast triggered, protocol resuming', swapId });
366
+ }
367
+ catch (err) {
368
+ const msg = err instanceof Error ? err.message : String(err);
369
+ const brokerNotReady = msg.includes('no swap awaiting broadcast');
370
+ if (!brokerNotReady) {
371
+ log.warn({ swapId, error: msg, attempt }, '[fund] /fund failed; aborting local retry');
372
+ break;
373
+ }
374
+ const backoffMs = Math.min(2000, 250 * 2 ** attempt);
375
+ log.info({ swapId, attempt, backoffMs }, '[fund] broker not yet armed, retrying /fund');
376
+ await delay(backoffMs);
377
+ }
378
+ }
379
+ if (!fundSucceeded) {
380
+ log.warn({ swapId }, '[fund] /fund did not succeed after local retries, will re-enter drive loop');
381
+ }
382
+ }
383
+ await delay(POLL_MS, signal);
384
+ continue;
385
+ }
386
+ if (action === 'submit_encsig') {
387
+ onProgress({ stage: 'submit_encsig', message: 'Computing encrypted signature', swapId });
388
+ const protocolParams = pdx.params;
389
+ if (!protocolParams) {
390
+ // Mirror of the fund-branch fix: the sidecar may briefly return
391
+ // action='submit_encsig' before protocolParams is flushed into
392
+ // provider_metadata. Wait and re-poll; the outer TIMEOUT_MS bounds
393
+ // the total wait.
394
+ log.debug({ swapId }, 'Submit-encsig requested but protocolParams not yet populated; waiting');
395
+ onProgress({
396
+ stage: 'submit_encsig',
397
+ message: 'Waiting for protocol params from sidecar',
398
+ swapId,
399
+ });
400
+ await delay(POLL_MS, signal);
401
+ continue;
402
+ }
403
+ if (!xmrLockVerified) {
404
+ const xmrVerif = pdx.xmrVerification;
405
+ if (!xmrVerif) {
406
+ onProgress({ stage: 'submit_encsig', message: 'Waiting for XMR lock verification data', swapId });
407
+ await delay(POLL_MS, signal);
408
+ continue;
409
+ }
410
+ onProgress({ stage: 'verifying_xmr', message: 'Verifying XMR lock on public node', swapId });
411
+ log.info({ swapId, txHash: xmrVerif.lock_transfer_proof.tx_hash }, 'Verifying XMR lock');
412
+ // AV-C.3: missing S_a_monero is a hard error.
413
+ const sAMon = protocolParams.S_a_monero;
414
+ const sBMon = keystore.keys.S_b_monero;
415
+ if (!sAMon || !sBMon) {
416
+ log.error({ swapId }, 'S_a_monero unavailable, cannot verify XMR lock');
417
+ throw new ProtocolError('E_S_A_MONERO_MISSING', 'S_a_monero not available; refusing to release encsig without XMR lock verification');
418
+ }
419
+ const combinedSpendPub = bytesToHex(Point.fromHex(sAMon).add(Point.fromHex(sBMon)).toBytes());
420
+ const lockResult = await verifyXmrLocked({
421
+ lockTxHash: xmrVerif.lock_transfer_proof.tx_hash,
422
+ viewKeyHex: xmrVerif.combined_view_key,
423
+ spendPubHex: combinedSpendPub,
424
+ expectedAmount: BigInt(xmrVerif.xmr_amount_pico),
425
+ minConfirmations: MIN_XMR_CONFIRMATIONS,
426
+ txKeyHex: xmrVerif.lock_transfer_proof.tx_key ?? undefined,
427
+ monerodNodes: options.monerodNodes,
428
+ logger: log,
429
+ });
430
+ if (!lockResult.verified) {
431
+ if (lockResult.retryable) {
432
+ onProgress({
433
+ stage: 'verifying_xmr',
434
+ message: `Waiting for XMR confirmations: ${lockResult.reason ?? 'pending'}`,
435
+ swapId,
436
+ });
437
+ await delay(POLL_MS, signal);
438
+ continue;
439
+ }
440
+ log.error({
441
+ swapId,
442
+ reason: lockResult.reason,
443
+ confirmations: lockResult.confirmations,
444
+ txHash: xmrVerif.lock_transfer_proof.tx_hash,
445
+ txKey: xmrVerif.lock_transfer_proof.tx_key,
446
+ lockAddress: xmrVerif.monero_lock_address,
447
+ expectedPico: xmrVerif.xmr_amount_pico,
448
+ viewKey: xmrVerif.combined_view_key,
449
+ combinedSpendPub,
450
+ }, 'XMR lock verification failed');
451
+ onProgress({
452
+ stage: 'error',
453
+ message: `XMR verification failed: ${lockResult.reason ?? 'unknown'}`,
454
+ swapId,
455
+ });
456
+ throw new VerificationError('E_XMR_LOCK_FAILED', lockResult.reason ?? 'XMR lock verification failed');
457
+ }
458
+ xmrLockVerified = true;
459
+ }
460
+ // The sidecar no longer surfaces `redeemDigestHex` over the wire (see
461
+ // extract.ts). When present we still compare byte-for-byte as defense in
462
+ // depth; when absent we fall back to the local computation alone — the
463
+ // signed PSBT or on-chain TxLock is the authoritative source either way.
464
+ const sidecarDigestHex = pdx.redeemDigestHex;
465
+ // AV-B.2: recompute the digest locally and (optionally) compare byte-for-byte before signing.
466
+ // Fresh-fund path: reuse the signed PSBT we kept in memory.
467
+ // Resume path: the PSBT is gone but TxLock is on-chain; fetch via the
468
+ // injected blockchain provider and recompute from the raw tx. Either
469
+ // path preserves the Fix 1 guarantee.
470
+ let localDigestHex;
471
+ if (lastSignedPsbt) {
472
+ localDigestHex = computeRedeemDigest({
473
+ signedPsbtBase64: lastSignedPsbt,
474
+ protocolParams,
475
+ bPubHex: keystore.keys.B,
476
+ network,
477
+ });
478
+ }
479
+ else {
480
+ if (!blockchain) {
481
+ throw new ProtocolError('E_NO_SIGNED_PSBT', 'resume path needs a blockchain provider to reconstruct the redeem digest');
482
+ }
483
+ const depositTxHash = detail.depositTxHash;
484
+ if (!depositTxHash) {
485
+ onProgress({
486
+ stage: 'submit_encsig',
487
+ message: 'Waiting for deposit tx hash from sidecar',
488
+ swapId,
489
+ });
490
+ await delay(POLL_MS, signal);
491
+ continue;
492
+ }
493
+ const lockTxRawHex = await blockchain.getTransaction(depositTxHash);
494
+ if (!lockTxRawHex) {
495
+ onProgress({
496
+ stage: 'submit_encsig',
497
+ message: 'Fetching TxLock from blockchain provider',
498
+ swapId,
499
+ });
500
+ await delay(POLL_MS, signal);
501
+ continue;
502
+ }
503
+ log.info({ swapId, depositTxHash, lockTxLen: lockTxRawHex.length }, 'Reconstructing redeem digest from on-chain TxLock (resume path)');
504
+ localDigestHex = computeRedeemDigestFromTxHex({
505
+ lockTxRawHex,
506
+ protocolParams,
507
+ bPubHex: keystore.keys.B,
508
+ network,
509
+ });
510
+ }
511
+ log.info({
512
+ swapId,
513
+ localDigestHex,
514
+ sidecarDigestHex,
515
+ source: lastSignedPsbt ? 'signed-psbt' : 'on-chain-txlock',
516
+ }, sidecarDigestHex
517
+ ? 'Comparing local redeem digest against sidecar claim'
518
+ : 'Sidecar digest unavailable; using local digest only');
519
+ if (sidecarDigestHex && !constantTimeEqualHex(localDigestHex, sidecarDigestHex)) {
520
+ log.error({ swapId, localDigestHex, sidecarDigestHex }, 'Redeem digest mismatch, refusing to release encsig');
521
+ throw new VerificationError('E_REDEEM_DIGEST_MISMATCH', 'local redeem digest does not match sidecar');
522
+ }
523
+ const txRedeemEncsig = encsignDigest(keystore.keys.b, protocolParams.S_a_bitcoin, localDigestHex);
524
+ onProgress({ stage: 'submit_encsig', message: 'Submitting encrypted signature', swapId });
525
+ try {
526
+ await api.executeAction(swapId, { type: 'submit_encsig', tx_redeem_encsig: txRedeemEncsig });
527
+ onProgress({ stage: 'confirming', message: 'Signature submitted, swap progressing', swapId });
528
+ encsigFailures = 0;
529
+ }
530
+ catch (err) {
531
+ encsigFailures++;
532
+ const msg = err instanceof Error ? err.message : String(err);
533
+ log.warn({ swapId, error: msg, attempt: encsigFailures }, 'Encsig submission failed');
534
+ if (encsigFailures >= MAX_ENCSIG_FAILURES) {
535
+ throw new ProtocolError('E_ENCSIG_SUBMIT_FAILED', `encsig submission failed ${String(MAX_ENCSIG_FAILURES)} times: ${msg}`);
536
+ }
537
+ onProgress({
538
+ stage: 'confirming',
539
+ message: `Encsig retry ${String(encsigFailures)}/${String(MAX_ENCSIG_FAILURES)}: ${msg}`,
540
+ swapId,
541
+ });
542
+ }
543
+ await delay(POLL_MS, signal);
544
+ continue;
545
+ }
546
+ if (action === 'sweep' || detail.status === 'sending') {
547
+ const pp = pdx.params;
548
+ if (!pp?.S_a_monero) {
549
+ throw new ProtocolError('E_PROTOCOL_PARAMS_MISSING', 'sweep requires S_a_monero in protocol params');
550
+ }
551
+ onProgress({ stage: 'sweeping', message: 'Sweeping XMR', swapId });
552
+ const sweepResult = await sweepMonero(api, {
553
+ swapId,
554
+ s_b: hexToBytes(keystore.keys.s_b),
555
+ receiveAddress: keystore.swap.receiveAddress,
556
+ expectedSAMonero: pp.S_a_monero,
557
+ monerodNodes: options.monerodNodes,
558
+ logger: log,
559
+ });
560
+ onProgress({
561
+ stage: 'complete',
562
+ message: `Sweep complete: ${sweepResult.txHash}`,
563
+ swapId,
564
+ txHash: sweepResult.txHash,
565
+ });
566
+ return;
567
+ }
568
+ if (action === 'cancel' || action === 'refund') {
569
+ onProgress({
570
+ stage: detail.status,
571
+ message: detail.requiredAction?.message ?? `Action: ${action}`,
572
+ swapId,
573
+ });
574
+ return;
575
+ }
576
+ onProgress({
577
+ stage: detail.status,
578
+ message: detail.requiredAction?.message ?? `Status: ${detail.status}`,
579
+ swapId,
580
+ });
581
+ await delay(POLL_MS, signal);
582
+ }
583
+ throw new ProtocolError('E_DRIVE_TIMEOUT', 'swap timed out waiting for progress');
584
+ }
585
+ /**
586
+ * Build a funding-proof payload (nonce + signature per UTXO) that the server
587
+ * requires when creating a swap.
588
+ *
589
+ * @internal
590
+ */
591
+ export function createFundingProof(wallet, deposit) {
592
+ const nonce = randomUuidV4();
593
+ const msgHash = sha256(new TextEncoder().encode(`${nonce}${wallet.address}`));
594
+ const sig = wallet.keyPair.sign(msgHash);
595
+ const signature = bytesToHex(new Uint8Array(sig));
596
+ const utxoList = deposit.utxos ?? [deposit];
597
+ const fundingProof = utxoList.map((u) => ({
598
+ txid: u.txid,
599
+ vout: u.vout,
600
+ value: u.value,
601
+ address: wallet.address,
602
+ nonce,
603
+ signature,
604
+ }));
605
+ return { fundingProof, nonce };
606
+ }
607
+ function extractPresigsEncsig(response) {
608
+ if (typeof response !== 'object' || response === null) {
609
+ return emptyPresigsEncsig();
610
+ }
611
+ const r = response;
612
+ if (typeof r.protocolData !== 'object' || r.protocolData === null) {
613
+ return emptyPresigsEncsig();
614
+ }
615
+ const pd = r.protocolData;
616
+ return {
617
+ txFullRefundEncsig: typeof pd['txFullRefundEncsig'] === 'string' ? pd['txFullRefundEncsig'] : null,
618
+ txPartialRefundEncsig: typeof pd['txPartialRefundEncsig'] === 'string' ? pd['txPartialRefundEncsig'] : null,
619
+ txCancelSig: typeof pd['txCancelSig'] === 'string' ? pd['txCancelSig'] : null,
620
+ txLockTxid: typeof pd['txLockTxid'] === 'string' ? pd['txLockTxid'] : null,
621
+ txLockVout: typeof pd['txLockVout'] === 'number' ? pd['txLockVout'] : null,
622
+ txLockAmountSats: typeof pd['txLockAmountSats'] === 'string' ? pd['txLockAmountSats'] : null,
623
+ };
624
+ }
625
+ function emptyPresigsEncsig() {
626
+ return {
627
+ txFullRefundEncsig: null,
628
+ txPartialRefundEncsig: null,
629
+ txCancelSig: null,
630
+ txLockTxid: null,
631
+ txLockVout: null,
632
+ txLockAmountSats: null,
633
+ };
634
+ }
635
+ async function maybeWriteSnapshot(input) {
636
+ if (!input.saveProtocolSnapshot)
637
+ return;
638
+ if (input.loadProtocolSnapshot) {
639
+ const existing = await input.loadProtocolSnapshot(input.swapId).catch(() => null);
640
+ if (existing) {
641
+ input.log.debug({ swapId: input.swapId }, 'Snapshot already on disk; skipping');
642
+ return;
643
+ }
644
+ }
645
+ const pp = input.protocolParams;
646
+ const snapshot = buildProtocolSnapshot({
647
+ swapId: input.swapId,
648
+ externalSwapId: input.externalSwapId,
649
+ keystoreId: input.keystoreId,
650
+ network: input.network,
651
+ capturedByVersion: input.clientVersion ?? 'unknown',
652
+ capturedAtEpochMs: Date.now(),
653
+ protocolParams: {
654
+ A: pp.A,
655
+ S_a_bitcoin: pp.S_a_bitcoin,
656
+ S_a_monero: pp.S_a_monero ?? '',
657
+ v_a: pp.v_a ?? null,
658
+ cancel_timelock: pp.cancel_timelock,
659
+ punish_timelock: pp.punish_timelock,
660
+ remaining_refund_timelock: pp.remaining_refund_timelock ?? null,
661
+ redeem_address: pp.redeem_address,
662
+ punish_address: pp.punish_address,
663
+ tx_cancel_fee_sats: String(pp.tx_cancel_fee_sats),
664
+ tx_refund_fee_sats: String(pp.tx_refund_fee_sats),
665
+ tx_redeem_fee_sats: String(pp.tx_redeem_fee_sats),
666
+ tx_punish_fee_sats: String(pp.tx_punish_fee_sats),
667
+ amnesty_amount_sats: pp.amnesty_amount_sats !== undefined ? String(pp.amnesty_amount_sats) : null,
668
+ tx_partial_refund_fee_sats: pp.tx_partial_refund_fee_sats !== undefined && pp.tx_partial_refund_fee_sats !== null
669
+ ? String(pp.tx_partial_refund_fee_sats)
670
+ : null,
671
+ tx_reclaim_fee_sats: pp.tx_reclaim_fee_sats !== undefined && pp.tx_reclaim_fee_sats !== null
672
+ ? String(pp.tx_reclaim_fee_sats)
673
+ : null,
674
+ tx_withhold_fee_sats: pp.tx_withhold_fee_sats !== undefined && pp.tx_withhold_fee_sats !== null
675
+ ? String(pp.tx_withhold_fee_sats)
676
+ : null,
677
+ tx_mercy_fee_sats: pp.tx_mercy_fee_sats !== undefined && pp.tx_mercy_fee_sats !== null
678
+ ? String(pp.tx_mercy_fee_sats)
679
+ : null,
680
+ monero_lock_address: pp.monero_lock_address ?? null,
681
+ xmr_amount_pico: pp.xmr_amount_pico ?? '0',
682
+ tx_full_refund_encsig: input.encsigFull,
683
+ tx_partial_refund_encsig: input.encsigPartial,
684
+ tx_cancel_sig: input.aliceTxCancelSig,
685
+ },
686
+ lockTx: {
687
+ txid: input.lockTxid,
688
+ vout: input.lockVout,
689
+ amountSats: input.lockAmountSats,
690
+ unsignedPsbtBase64: input.unsignedPsbtBase64,
691
+ lockAddress: input.lockAddress,
692
+ },
693
+ maker: {
694
+ peerId: input.makerPeerId ?? '',
695
+ multiaddrs: input.makerMultiaddrs ?? [],
696
+ },
697
+ chain: {
698
+ moneroWalletRestoreBlockheight: input.xmrVerification?.monero_restore_height ?? null,
699
+ lockTransferProof: input.xmrVerification?.lock_transfer_proof ?? null,
700
+ sidecarStateAtCapture: input.sidecarStateAtCapture,
701
+ },
702
+ });
703
+ try {
704
+ await input.saveProtocolSnapshot(input.swapId, JSON.stringify(snapshot, null, 2));
705
+ input.log.info({ swapId: input.swapId, externalSwapId: input.externalSwapId }, 'Snapshot persisted');
706
+ }
707
+ catch (err) {
708
+ const msg = err instanceof Error ? err.message : String(err);
709
+ input.log.warn({ swapId: input.swapId, error: msg }, 'Failed to persist snapshot');
710
+ throw new ProtocolError('E_SNAPSHOT_WRITE_FAILED', `Refusing to broadcast lock tx without a persisted snapshot: ${msg}`);
711
+ }
712
+ }
713
+ //# sourceMappingURL=drive.js.map