@atomiqlabs/sdk 8.9.1 → 8.9.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 (366) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +1760 -1760
  3. package/api/index.d.ts +1 -1
  4. package/api/index.js +3 -3
  5. package/dist/ApiList.d.ts +37 -37
  6. package/dist/ApiList.js +30 -30
  7. package/dist/SmartChainAssets.d.ts +181 -181
  8. package/dist/SmartChainAssets.js +181 -181
  9. package/dist/api/ApiEndpoints.d.ts +393 -393
  10. package/dist/api/ApiEndpoints.js +2 -2
  11. package/dist/api/ApiParser.d.ts +10 -10
  12. package/dist/api/ApiParser.js +134 -134
  13. package/dist/api/ApiTypes.d.ts +157 -157
  14. package/dist/api/ApiTypes.js +75 -75
  15. package/dist/api/SerializedAction.d.ts +40 -40
  16. package/dist/api/SerializedAction.js +59 -59
  17. package/dist/api/SwapperApi.d.ts +50 -50
  18. package/dist/api/SwapperApi.js +431 -431
  19. package/dist/api/index.d.ts +5 -5
  20. package/dist/api/index.js +24 -24
  21. package/dist/bitcoin/coinselect2/accumulative.d.ts +7 -7
  22. package/dist/bitcoin/coinselect2/accumulative.js +52 -52
  23. package/dist/bitcoin/coinselect2/blackjack.d.ts +7 -7
  24. package/dist/bitcoin/coinselect2/blackjack.js +38 -38
  25. package/dist/bitcoin/coinselect2/index.d.ts +20 -20
  26. package/dist/bitcoin/coinselect2/index.js +69 -69
  27. package/dist/bitcoin/coinselect2/utils.d.ts +82 -82
  28. package/dist/bitcoin/coinselect2/utils.js +158 -158
  29. package/dist/bitcoin/wallet/BitcoinWallet.d.ts +113 -113
  30. package/dist/bitcoin/wallet/BitcoinWallet.js +335 -335
  31. package/dist/bitcoin/wallet/IBitcoinWallet.d.ts +116 -116
  32. package/dist/bitcoin/wallet/IBitcoinWallet.js +21 -21
  33. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.d.ts +106 -106
  34. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.js +196 -196
  35. package/dist/enums/FeeType.d.ts +15 -15
  36. package/dist/enums/FeeType.js +19 -19
  37. package/dist/enums/SwapAmountType.d.ts +15 -15
  38. package/dist/enums/SwapAmountType.js +19 -19
  39. package/dist/enums/SwapDirection.d.ts +15 -15
  40. package/dist/enums/SwapDirection.js +19 -19
  41. package/dist/enums/SwapSide.d.ts +15 -15
  42. package/dist/enums/SwapSide.js +19 -19
  43. package/dist/enums/SwapType.d.ts +75 -75
  44. package/dist/enums/SwapType.js +79 -79
  45. package/dist/errors/IntermediaryError.d.ts +13 -13
  46. package/dist/errors/IntermediaryError.js +27 -27
  47. package/dist/errors/RequestError.d.ts +32 -32
  48. package/dist/errors/RequestError.js +54 -54
  49. package/dist/errors/UserError.d.ts +8 -8
  50. package/dist/errors/UserError.js +16 -16
  51. package/dist/events/UnifiedSwapEventListener.d.ts +24 -24
  52. package/dist/events/UnifiedSwapEventListener.js +138 -138
  53. package/dist/http/HttpUtils.d.ts +29 -29
  54. package/dist/http/HttpUtils.js +97 -97
  55. package/dist/http/paramcoders/IParamReader.d.ts +8 -8
  56. package/dist/http/paramcoders/IParamReader.js +2 -2
  57. package/dist/http/paramcoders/ParamDecoder.d.ts +44 -44
  58. package/dist/http/paramcoders/ParamDecoder.js +137 -137
  59. package/dist/http/paramcoders/ParamEncoder.d.ts +20 -20
  60. package/dist/http/paramcoders/ParamEncoder.js +36 -36
  61. package/dist/http/paramcoders/SchemaVerifier.d.ts +26 -26
  62. package/dist/http/paramcoders/SchemaVerifier.js +145 -145
  63. package/dist/http/paramcoders/client/ResponseParamDecoder.d.ts +11 -11
  64. package/dist/http/paramcoders/client/ResponseParamDecoder.js +57 -57
  65. package/dist/http/paramcoders/client/StreamParamEncoder.d.ts +13 -13
  66. package/dist/http/paramcoders/client/StreamParamEncoder.js +26 -26
  67. package/dist/http/paramcoders/client/StreamingFetchPromise.d.ts +17 -17
  68. package/dist/http/paramcoders/client/StreamingFetchPromise.js +175 -175
  69. package/dist/index.d.ts +86 -86
  70. package/dist/index.js +159 -159
  71. package/dist/intermediaries/Intermediary.d.ts +178 -178
  72. package/dist/intermediaries/Intermediary.js +166 -166
  73. package/dist/intermediaries/IntermediaryDiscovery.d.ts +216 -216
  74. package/dist/intermediaries/IntermediaryDiscovery.js +424 -424
  75. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +607 -607
  76. package/dist/intermediaries/apis/IntermediaryAPI.js +764 -764
  77. package/dist/intermediaries/apis/TrustedIntermediaryAPI.d.ts +155 -155
  78. package/dist/intermediaries/apis/TrustedIntermediaryAPI.js +137 -137
  79. package/dist/intermediaries/auth/SignedKeyBasedAuth.d.ts +14 -14
  80. package/dist/intermediaries/auth/SignedKeyBasedAuth.js +68 -68
  81. package/dist/lnurl/LNURL.d.ts +102 -102
  82. package/dist/lnurl/LNURL.js +321 -321
  83. package/dist/prices/RedundantSwapPrice.d.ts +110 -110
  84. package/dist/prices/RedundantSwapPrice.js +222 -222
  85. package/dist/prices/SingleSwapPrice.d.ts +34 -34
  86. package/dist/prices/SingleSwapPrice.js +44 -44
  87. package/dist/prices/SwapPriceWithChain.d.ts +107 -107
  88. package/dist/prices/SwapPriceWithChain.js +128 -128
  89. package/dist/prices/abstract/ICachedSwapPrice.d.ts +28 -28
  90. package/dist/prices/abstract/ICachedSwapPrice.js +62 -62
  91. package/dist/prices/abstract/IPriceProvider.d.ts +81 -81
  92. package/dist/prices/abstract/IPriceProvider.js +74 -74
  93. package/dist/prices/abstract/ISwapPrice.d.ts +168 -168
  94. package/dist/prices/abstract/ISwapPrice.js +279 -279
  95. package/dist/prices/providers/BinancePriceProvider.d.ts +23 -23
  96. package/dist/prices/providers/BinancePriceProvider.js +30 -30
  97. package/dist/prices/providers/CoinGeckoPriceProvider.d.ts +23 -23
  98. package/dist/prices/providers/CoinGeckoPriceProvider.js +29 -29
  99. package/dist/prices/providers/CoinPaprikaPriceProvider.d.ts +25 -25
  100. package/dist/prices/providers/CoinPaprikaPriceProvider.js +29 -29
  101. package/dist/prices/providers/CustomPriceProvider.d.ts +24 -24
  102. package/dist/prices/providers/CustomPriceProvider.js +35 -35
  103. package/dist/prices/providers/KrakenPriceProvider.d.ts +38 -38
  104. package/dist/prices/providers/KrakenPriceProvider.js +45 -45
  105. package/dist/prices/providers/OKXPriceProvider.d.ts +34 -34
  106. package/dist/prices/providers/OKXPriceProvider.js +29 -29
  107. package/dist/prices/providers/abstract/ExchangePriceProvider.d.ts +17 -17
  108. package/dist/prices/providers/abstract/ExchangePriceProvider.js +21 -21
  109. package/dist/prices/providers/abstract/HttpPriceProvider.d.ts +7 -7
  110. package/dist/prices/providers/abstract/HttpPriceProvider.js +12 -12
  111. package/dist/storage/IUnifiedStorage.d.ts +127 -127
  112. package/dist/storage/IUnifiedStorage.js +2 -2
  113. package/dist/storage/UnifiedSwapStorage.d.ts +120 -120
  114. package/dist/storage/UnifiedSwapStorage.js +154 -154
  115. package/dist/storage-browser/IndexedDBUnifiedStorage.d.ts +63 -63
  116. package/dist/storage-browser/IndexedDBUnifiedStorage.js +298 -298
  117. package/dist/storage-browser/LocalStorageManager.d.ts +49 -49
  118. package/dist/storage-browser/LocalStorageManager.js +93 -93
  119. package/dist/swapper/Swapper.d.ts +770 -770
  120. package/dist/swapper/Swapper.js +1758 -1758
  121. package/dist/swapper/SwapperFactory.d.ts +135 -135
  122. package/dist/swapper/SwapperFactory.js +162 -162
  123. package/dist/swapper/SwapperUtils.d.ts +222 -222
  124. package/dist/swapper/SwapperUtils.js +519 -519
  125. package/dist/swapper/SwapperWithChain.d.ts +404 -404
  126. package/dist/swapper/SwapperWithChain.js +469 -469
  127. package/dist/swapper/SwapperWithSigner.d.ts +322 -322
  128. package/dist/swapper/SwapperWithSigner.js +318 -318
  129. package/dist/swaps/IAddressSwap.d.ts +22 -22
  130. package/dist/swaps/IAddressSwap.js +14 -14
  131. package/dist/swaps/IBTCWalletSwap.d.ts +73 -73
  132. package/dist/swaps/IBTCWalletSwap.js +18 -18
  133. package/dist/swaps/IClaimableSwap.d.ts +49 -49
  134. package/dist/swaps/IClaimableSwap.js +15 -15
  135. package/dist/swaps/IClaimableSwapWrapper.d.ts +15 -15
  136. package/dist/swaps/IClaimableSwapWrapper.js +2 -2
  137. package/dist/swaps/IRefundableSwap.d.ts +43 -43
  138. package/dist/swaps/IRefundableSwap.js +14 -14
  139. package/dist/swaps/ISwap.d.ts +453 -453
  140. package/dist/swaps/ISwap.js +371 -371
  141. package/dist/swaps/ISwapWithGasDrop.d.ts +21 -21
  142. package/dist/swaps/ISwapWithGasDrop.js +12 -12
  143. package/dist/swaps/ISwapWrapper.d.ts +295 -295
  144. package/dist/swaps/ISwapWrapper.js +373 -373
  145. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.d.ts +98 -98
  146. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.js +126 -126
  147. package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +139 -139
  148. package/dist/swaps/escrow_swaps/IEscrowSwap.js +172 -172
  149. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +129 -129
  150. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +167 -167
  151. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +107 -107
  152. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +130 -130
  153. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.d.ts +162 -162
  154. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +190 -190
  155. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.d.ts +64 -64
  156. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.js +82 -82
  157. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +547 -547
  158. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +1419 -1419
  159. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +192 -192
  160. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +432 -432
  161. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +650 -650
  162. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +1577 -1577
  163. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +237 -237
  164. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +525 -525
  165. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +491 -491
  166. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +1463 -1463
  167. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +204 -204
  168. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +406 -406
  169. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +446 -446
  170. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +1097 -1097
  171. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.d.ts +68 -68
  172. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +117 -117
  173. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.d.ts +127 -127
  174. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.js +256 -256
  175. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +252 -252
  176. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +535 -535
  177. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.d.ts +73 -73
  178. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.js +155 -155
  179. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +134 -134
  180. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +286 -286
  181. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +694 -694
  182. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +1687 -1687
  183. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +259 -259
  184. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +947 -947
  185. package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +302 -302
  186. package/dist/swaps/trusted/ln/LnForGasSwap.js +625 -625
  187. package/dist/swaps/trusted/ln/LnForGasWrapper.d.ts +40 -40
  188. package/dist/swaps/trusted/ln/LnForGasWrapper.js +82 -82
  189. package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +343 -343
  190. package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +698 -698
  191. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.d.ts +71 -71
  192. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +93 -93
  193. package/dist/types/AmountData.d.ts +10 -10
  194. package/dist/types/AmountData.js +2 -2
  195. package/dist/types/CustomPriceFunction.d.ts +11 -11
  196. package/dist/types/CustomPriceFunction.js +2 -2
  197. package/dist/types/PriceInfoType.d.ts +28 -28
  198. package/dist/types/PriceInfoType.js +57 -57
  199. package/dist/types/SwapExecutionAction.d.ts +195 -195
  200. package/dist/types/SwapExecutionAction.js +106 -106
  201. package/dist/types/SwapExecutionStep.d.ts +144 -144
  202. package/dist/types/SwapExecutionStep.js +87 -87
  203. package/dist/types/SwapStateInfo.d.ts +5 -5
  204. package/dist/types/SwapStateInfo.js +2 -2
  205. package/dist/types/SwapWithSigner.d.ts +17 -17
  206. package/dist/types/SwapWithSigner.js +43 -43
  207. package/dist/types/Token.d.ts +99 -99
  208. package/dist/types/Token.js +76 -76
  209. package/dist/types/TokenAmount.d.ts +75 -75
  210. package/dist/types/TokenAmount.js +85 -85
  211. package/dist/types/fees/Fee.d.ts +50 -50
  212. package/dist/types/fees/Fee.js +2 -2
  213. package/dist/types/fees/FeeBreakdown.d.ts +11 -11
  214. package/dist/types/fees/FeeBreakdown.js +2 -2
  215. package/dist/types/fees/PercentagePPM.d.ts +17 -17
  216. package/dist/types/fees/PercentagePPM.js +18 -18
  217. package/dist/types/lnurl/LNURLPay.d.ts +61 -61
  218. package/dist/types/lnurl/LNURLPay.js +31 -31
  219. package/dist/types/lnurl/LNURLWithdraw.d.ts +48 -48
  220. package/dist/types/lnurl/LNURLWithdraw.js +27 -27
  221. package/dist/types/wallets/LightningInvoiceCreateService.d.ts +24 -24
  222. package/dist/types/wallets/LightningInvoiceCreateService.js +15 -15
  223. package/dist/types/wallets/MinimalBitcoinWalletInterface.d.ts +23 -23
  224. package/dist/types/wallets/MinimalBitcoinWalletInterface.js +2 -2
  225. package/dist/types/wallets/MinimalLightningNetworkWalletInterface.d.ts +9 -9
  226. package/dist/types/wallets/MinimalLightningNetworkWalletInterface.js +2 -2
  227. package/dist/utils/AutomaticClockDriftCorrection.d.ts +1 -1
  228. package/dist/utils/AutomaticClockDriftCorrection.js +70 -70
  229. package/dist/utils/BitcoinUtils.d.ts +18 -18
  230. package/dist/utils/BitcoinUtils.js +174 -174
  231. package/dist/utils/BitcoinWalletUtils.d.ts +7 -7
  232. package/dist/utils/BitcoinWalletUtils.js +14 -14
  233. package/dist/utils/Logger.d.ts +7 -7
  234. package/dist/utils/Logger.js +12 -12
  235. package/dist/utils/RetryUtils.d.ts +22 -22
  236. package/dist/utils/RetryUtils.js +67 -67
  237. package/dist/utils/SwapUtils.d.ts +88 -88
  238. package/dist/utils/SwapUtils.js +72 -72
  239. package/dist/utils/TimeoutUtils.d.ts +17 -17
  240. package/dist/utils/TimeoutUtils.js +55 -55
  241. package/dist/utils/TokenUtils.d.ts +19 -19
  242. package/dist/utils/TokenUtils.js +37 -37
  243. package/dist/utils/TypeUtils.d.ts +7 -7
  244. package/dist/utils/TypeUtils.js +2 -2
  245. package/dist/utils/Utils.d.ts +69 -69
  246. package/dist/utils/Utils.js +214 -214
  247. package/package.json +46 -46
  248. package/src/SmartChainAssets.ts +186 -186
  249. package/src/api/ApiEndpoints.ts +427 -427
  250. package/src/api/ApiParser.ts +138 -138
  251. package/src/api/ApiTypes.ts +229 -229
  252. package/src/api/SerializedAction.ts +97 -97
  253. package/src/api/SwapperApi.ts +545 -545
  254. package/src/api/index.ts +5 -5
  255. package/src/bitcoin/coinselect2/accumulative.ts +69 -69
  256. package/src/bitcoin/coinselect2/blackjack.ts +50 -50
  257. package/src/bitcoin/coinselect2/index.ts +93 -93
  258. package/src/bitcoin/coinselect2/utils.ts +236 -236
  259. package/src/bitcoin/wallet/BitcoinWallet.ts +439 -439
  260. package/src/bitcoin/wallet/IBitcoinWallet.ts +140 -140
  261. package/src/bitcoin/wallet/SingleAddressBitcoinWallet.ts +225 -225
  262. package/src/enums/FeeType.ts +15 -15
  263. package/src/enums/SwapAmountType.ts +16 -16
  264. package/src/enums/SwapDirection.ts +15 -15
  265. package/src/enums/SwapSide.ts +16 -16
  266. package/src/enums/SwapType.ts +75 -75
  267. package/src/errors/IntermediaryError.ts +28 -28
  268. package/src/errors/RequestError.ts +64 -64
  269. package/src/errors/UserError.ts +15 -15
  270. package/src/events/UnifiedSwapEventListener.ts +181 -181
  271. package/src/http/HttpUtils.ts +97 -97
  272. package/src/http/paramcoders/IParamReader.ts +9 -9
  273. package/src/http/paramcoders/ParamDecoder.ts +145 -145
  274. package/src/http/paramcoders/ParamEncoder.ts +40 -40
  275. package/src/http/paramcoders/SchemaVerifier.ts +153 -153
  276. package/src/http/paramcoders/client/ResponseParamDecoder.ts +57 -57
  277. package/src/http/paramcoders/client/StreamParamEncoder.ts +28 -28
  278. package/src/http/paramcoders/client/StreamingFetchPromise.ts +194 -194
  279. package/src/index.ts +141 -141
  280. package/src/intermediaries/Intermediary.ts +280 -280
  281. package/src/intermediaries/IntermediaryDiscovery.ts +548 -548
  282. package/src/intermediaries/apis/IntermediaryAPI.ts +1247 -1247
  283. package/src/intermediaries/auth/SignedKeyBasedAuth.ts +69 -69
  284. package/src/lnurl/LNURL.ts +402 -402
  285. package/src/prices/RedundantSwapPrice.ts +264 -264
  286. package/src/prices/SingleSwapPrice.ts +50 -50
  287. package/src/prices/SwapPriceWithChain.ts +194 -194
  288. package/src/prices/abstract/ICachedSwapPrice.ts +85 -85
  289. package/src/prices/abstract/IPriceProvider.ts +127 -127
  290. package/src/prices/abstract/ISwapPrice.ts +390 -390
  291. package/src/prices/providers/BinancePriceProvider.ts +48 -48
  292. package/src/prices/providers/CoinGeckoPriceProvider.ts +46 -46
  293. package/src/prices/providers/CoinPaprikaPriceProvider.ts +49 -49
  294. package/src/prices/providers/CustomPriceProvider.ts +40 -40
  295. package/src/prices/providers/KrakenPriceProvider.ts +83 -83
  296. package/src/prices/providers/OKXPriceProvider.ts +59 -59
  297. package/src/prices/providers/abstract/ExchangePriceProvider.ts +31 -31
  298. package/src/prices/providers/abstract/HttpPriceProvider.ts +14 -14
  299. package/src/storage/IUnifiedStorage.ts +136 -136
  300. package/src/storage/UnifiedSwapStorage.ts +175 -175
  301. package/src/storage-browser/IndexedDBUnifiedStorage.ts +350 -350
  302. package/src/storage-browser/LocalStorageManager.ts +106 -106
  303. package/src/swapper/Swapper.ts +2570 -2570
  304. package/src/swapper/SwapperFactory.ts +307 -307
  305. package/src/swapper/SwapperUtils.ts +610 -610
  306. package/src/swapper/SwapperWithChain.ts +707 -707
  307. package/src/swapper/SwapperWithSigner.ts +511 -511
  308. package/src/swaps/IAddressSwap.ts +30 -30
  309. package/src/swaps/IBTCWalletSwap.ts +92 -92
  310. package/src/swaps/IClaimableSwap.ts +65 -65
  311. package/src/swaps/IClaimableSwapWrapper.ts +17 -17
  312. package/src/swaps/IRefundableSwap.ts +58 -58
  313. package/src/swaps/ISwap.ts +775 -775
  314. package/src/swaps/ISwapWithGasDrop.ts +25 -25
  315. package/src/swaps/ISwapWrapper.ts +564 -564
  316. package/src/swaps/escrow_swaps/IEscrowSelfInitSwap.ts +217 -217
  317. package/src/swaps/escrow_swaps/IEscrowSwap.ts +271 -271
  318. package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +284 -284
  319. package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +172 -172
  320. package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +300 -300
  321. package/src/swaps/escrow_swaps/frombtc/IFromBTCWrapper.ts +107 -107
  322. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +1670 -1671
  323. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +603 -603
  324. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +1883 -1883
  325. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +752 -752
  326. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +1753 -1753
  327. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +612 -612
  328. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +1327 -1327
  329. package/src/swaps/escrow_swaps/tobtc/IToBTCWrapper.ts +138 -138
  330. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.ts +304 -304
  331. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +787 -787
  332. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.ts +206 -206
  333. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +403 -403
  334. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +2148 -2148
  335. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +1238 -1238
  336. package/src/swaps/trusted/ln/LnForGasSwap.ts +753 -753
  337. package/src/swaps/trusted/ln/LnForGasWrapper.ts +90 -90
  338. package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +843 -843
  339. package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +133 -133
  340. package/src/types/AmountData.ts +9 -9
  341. package/src/types/CustomPriceFunction.ts +11 -11
  342. package/src/types/PriceInfoType.ts +66 -66
  343. package/src/types/SwapExecutionAction.ts +323 -323
  344. package/src/types/SwapExecutionStep.ts +224 -224
  345. package/src/types/SwapStateInfo.ts +6 -6
  346. package/src/types/SwapWithSigner.ts +61 -61
  347. package/src/types/Token.ts +163 -163
  348. package/src/types/TokenAmount.ts +167 -167
  349. package/src/types/fees/Fee.ts +56 -56
  350. package/src/types/fees/FeeBreakdown.ts +11 -11
  351. package/src/types/fees/PercentagePPM.ts +26 -26
  352. package/src/types/lnurl/LNURLPay.ts +79 -79
  353. package/src/types/lnurl/LNURLWithdraw.ts +61 -61
  354. package/src/types/wallets/LightningInvoiceCreateService.ts +30 -30
  355. package/src/types/wallets/MinimalBitcoinWalletInterface.ts +21 -21
  356. package/src/types/wallets/MinimalLightningNetworkWalletInterface.ts +9 -9
  357. package/src/utils/AutomaticClockDriftCorrection.ts +71 -71
  358. package/src/utils/BitcoinUtils.ts +164 -164
  359. package/src/utils/BitcoinWalletUtils.ts +15 -15
  360. package/src/utils/Logger.ts +14 -14
  361. package/src/utils/RetryUtils.ts +78 -78
  362. package/src/utils/SwapUtils.ts +99 -99
  363. package/src/utils/TimeoutUtils.ts +49 -49
  364. package/src/utils/TokenUtils.ts +33 -33
  365. package/src/utils/TypeUtils.ts +8 -8
  366. package/src/utils/Utils.ts +221 -221
@@ -1,545 +1,545 @@
1
- import {MultiChain, Swapper} from "../swapper/Swapper";
2
- import {ApiEndpoint, createApiEndpoint, toApiAmount, toApiLNURL, toApiToken} from "./ApiTypes";
3
- import {ISwap} from "../swaps/ISwap";
4
- import {serializeAction} from "./SerializedAction";
5
- import {FeeType} from "../enums/FeeType";
6
- import {SwapSide} from "../enums/SwapSide";
7
- import {SwapType} from "../enums/SwapType";
8
- import {MinimalBitcoinWalletInterface} from "../types/wallets/MinimalBitcoinWalletInterface";
9
- import {FromBTCLNSwap, FromBTCLNSwapState} from "../swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap";
10
- import {FromBTCLNAutoSwap, FromBTCLNAutoSwapState} from "../swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap";
11
- import {
12
- CreateSwapInput,
13
- CreateSwapOutput,
14
- GetSpendableBalanceInput,
15
- GetSpendableBalanceOutput,
16
- GetSupportedTokensInput,
17
- GetSupportedTokensOutput,
18
- GetSwapCounterTokensInput,
19
- GetSwapCounterTokensOutput,
20
- GetSwapLimitsInput,
21
- GetSwapLimitsOutput,
22
- GetSwapStatusInput,
23
- GetSwapStatusOutput,
24
- ListPendingSwapsInput,
25
- ListPendingSwapsOutput,
26
- ListSwapOutput,
27
- ListSwapsInput,
28
- ListSwapsOutput,
29
- ParseAddressInput,
30
- ParseAddressOutput,
31
- SettleWithLnurlInput,
32
- SettleWithLnurlOutput,
33
- SubmitTransactionInput,
34
- SubmitTransactionOutput,
35
- SwapOutputBase
36
- } from "./ApiEndpoints";
37
- import {SwapExecutionStep} from "../types/SwapExecutionStep";
38
- import {SwapStateInfo} from "../types/SwapStateInfo";
39
- import {IEscrowSwap} from "../swaps/escrow_swaps/IEscrowSwap";
40
- import {ToBTCLNSwap} from "../swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap";
41
-
42
- function requiresSecretRevealForApi(swap: ISwap, state: number): boolean | undefined {
43
- if(swap instanceof FromBTCLNSwap) {
44
- if(swap.hasSecretPreimage()) return false;
45
- return state===FromBTCLNSwapState.PR_PAID || state===FromBTCLNSwapState.CLAIM_COMMITED;
46
- }
47
- if(swap instanceof FromBTCLNAutoSwap) {
48
- if(swap.hasSecretPreimage()) return false;
49
- return state===FromBTCLNAutoSwapState.CLAIM_COMMITED;
50
- }
51
- }
52
-
53
- function createSwapOutputBase(
54
- swap: ISwap,
55
- steps: SwapExecutionStep[],
56
- stateInfo: SwapStateInfo<number>
57
- ): SwapOutputBase {
58
- const input = swap.getInput();
59
- const output = swap.getOutput();
60
- const feeBreakdown = swap.getFeeBreakdown();
61
-
62
- // Build fees from breakdown
63
- const swapFeeEntry = feeBreakdown.find(f => f.type === FeeType.SWAP);
64
- const networkFeeEntry = feeBreakdown.find(f => f.type === FeeType.NETWORK_OUTPUT);
65
-
66
- return {
67
- swapId: swap.getId(),
68
- swapType: SwapType[swap.getType()],
69
-
70
- state: {
71
- number: stateInfo.state,
72
- name: stateInfo.name,
73
- description: stateInfo.description
74
- },
75
-
76
- quote: {
77
- inputAmount: toApiAmount(input),
78
- outputAmount: toApiAmount(output),
79
- fees: {
80
- swap: swapFeeEntry
81
- ? toApiAmount(swapFeeEntry.fee.amountInSrcToken)
82
- : { amount: "0", rawAmount: "0", decimals: 0, symbol: "", chain: "" },
83
- ...(networkFeeEntry ? {
84
- networkOutput: toApiAmount(networkFeeEntry.fee.amountInSrcToken)
85
- } : {})
86
- },
87
- expiry: swap.getQuoteExpiry(),
88
- outputAddress: swap.getOutputAddress()!
89
- },
90
-
91
- createdAt: swap.createdAt,
92
-
93
- steps,
94
-
95
- ...(swap instanceof ToBTCLNSwap && swap.isLNURL() ? {
96
- lnurl: {
97
- pay: swap.getLNURL()!,
98
- successAction: swap.getSuccessAction() ?? undefined
99
- }
100
- } : (swap instanceof FromBTCLNSwap || swap instanceof FromBTCLNAutoSwap) && swap.isLNURL() ? {
101
- lnurl: {
102
- withdraw: swap.getLNURL()!,
103
- }
104
- } : {})
105
- };
106
- }
107
-
108
- function createListSwapOutput(
109
- swap: ISwap,
110
- steps: SwapExecutionStep[],
111
- stateInfo: SwapStateInfo<number>
112
- ): ListSwapOutput {
113
- return {
114
- ...createSwapOutputBase(swap, steps, stateInfo),
115
-
116
- isFinished: swap.isFinished(),
117
- isSuccess: swap.isSuccessful(),
118
- isFailed: swap.isFailed(),
119
- isExpired: swap.isQuoteExpired()
120
- };
121
- }
122
-
123
- function parseSwapSide(side: "INPUT" | "OUTPUT"): SwapSide {
124
- return side === "INPUT" ? SwapSide.INPUT : SwapSide.OUTPUT;
125
- }
126
-
127
- export type SwapperApiConfig = {
128
- syncOnGetStatus?: boolean,
129
- idempotentTxSubmission?: boolean
130
- };
131
-
132
- export class SwapperApi<T extends MultiChain> {
133
-
134
- readonly endpoints: {
135
- createSwap: ApiEndpoint<CreateSwapInput, CreateSwapOutput, "POST">;
136
- listSwaps: ApiEndpoint<ListSwapsInput, ListSwapsOutput, "GET">;
137
- listPendingSwaps: ApiEndpoint<ListPendingSwapsInput, ListPendingSwapsOutput, "GET">;
138
- getSupportedTokens: ApiEndpoint<GetSupportedTokensInput, GetSupportedTokensOutput, "GET">;
139
- getSwapCounterTokens: ApiEndpoint<GetSwapCounterTokensInput, GetSwapCounterTokensOutput, "GET">;
140
- getSwapLimits: ApiEndpoint<GetSwapLimitsInput, GetSwapLimitsOutput, "GET">;
141
- parseAddress: ApiEndpoint<ParseAddressInput, ParseAddressOutput, "GET">;
142
- getSpendableBalance: ApiEndpoint<GetSpendableBalanceInput, GetSpendableBalanceOutput, "GET">;
143
- getSwapStatus: ApiEndpoint<GetSwapStatusInput, GetSwapStatusOutput, "GET">;
144
- submitTransaction: ApiEndpoint<SubmitTransactionInput, SubmitTransactionOutput, "POST">;
145
- settleWithLnurl: ApiEndpoint<SettleWithLnurlInput, SettleWithLnurlOutput, "POST">;
146
- };
147
-
148
- constructor(private swapper: Swapper<T>, private readonly config?: SwapperApiConfig) {
149
- this.config ??= {};
150
- this.config.syncOnGetStatus ??= true;
151
- this.endpoints = {
152
- createSwap: createApiEndpoint<CreateSwapInput, CreateSwapOutput, "POST">("POST", "Create a new cross-chain atomic swap. Returns a swap object with swapId, swapType, state, createdAt, quote (with inputAmount and outputAmount as ApiAmount objects each having amount/rawAmount/decimals/symbol/chain, a fees breakdown {swap, networkOutput?} of ApiAmount values, expiry, and outputAddress), a steps array, and optional lnurl. After creation, poll getSwapStatus periodically to get the next required action.", this.createSwap.bind(this), {
153
- srcToken: { type: "string", required: true, description: "Source token ticker (e.g. 'BITCOIN-BTC', 'LIGHTNING-BTC', 'STARKNET-STRK', 'SOLANA-SOL')" },
154
- dstToken: { type: "string", required: true, description: "Destination token ticker" },
155
- amount: { type: "bigint", required: true, description: "Amount in base units as an integer" },
156
- amountType: { type: "string", required: true, description: "EXACT_IN or EXACT_OUT", allowedValues: ["EXACT_IN", "EXACT_OUT"] },
157
- srcAddress: { type: "string", required: false, description: "Source address (only required for Smart chain -> BTC/Lightning swaps)" },
158
- dstAddress: { type: "string", required: true, description: "Destination address" },
159
- gasAmount: { type: "bigint", required: false, description: "Gas token amount to receive on destination chain, in base units" },
160
- paymentHash: { type: "string", required: false, description: "Custom payment hash for Lightning swaps" },
161
- lightningInvoiceDescription: { type: "string", required: false, description: "Description for Lightning invoice" },
162
- lightningInvoiceDescriptionHash: { type: "string", required: false, description: "Description hash for Lightning invoice (hex)" },
163
- lightningPaymentHTLCTimeout: { type: "number", required: false, description: "Custom expiry time in seconds" }
164
- }),
165
- listSwaps: createApiEndpoint<ListSwapsInput, ListSwapsOutput, "GET">("GET", "List all swaps for a given signer address. Returns an array of swap objects, each with swapId, swapType, state, quote, steps, and terminal state flags (isFinished, isSuccess, isFailed, isExpired). Optionally filter by smart chain.", this.listSwaps.bind(this), {
166
- signer: { type: "string", required: true, description: "Smart chain signer address to filter swaps for" },
167
- chainId: { type: "string", required: false, description: "Optional smart chain identifier to filter swaps" }
168
- }),
169
- listPendingSwaps: createApiEndpoint<ListPendingSwapsInput, ListPendingSwapsOutput, "GET">("GET", "List swaps that require user action for a given signer address. Returns an array of swap objects with the same structure as listSwaps.", this.listPendingSwaps.bind(this), {
170
- signer: { type: "string", required: true, description: "Smart chain signer address to filter pending swaps for" },
171
- chainId: { type: "string", required: false, description: "Optional smart chain identifier to filter pending swaps" }
172
- }),
173
- getSupportedTokens: createApiEndpoint<GetSupportedTokensInput, GetSupportedTokensOutput, "GET">("GET", "List all tokens available as swap input or output. Returns an array of ApiToken objects, each with id (e.g. BITCOIN-BTC, LIGHTNING-BTC, STARKNET-STRK), chainId, ticker, name, decimals, and address.", this.getSupportedTokens.bind(this), {
174
- side: {
175
- type: "string",
176
- required: true,
177
- description: "Whether to list valid source tokens (INPUT) or destination tokens (OUTPUT)",
178
- allowedValues: ["INPUT", "OUTPUT"]
179
- }
180
- }),
181
- getSwapCounterTokens: createApiEndpoint<GetSwapCounterTokensInput, GetSwapCounterTokensOutput, "GET">("GET", "Get tokens that can be swapped against a given token. Returns an array of ApiToken objects (id, chainId, ticker, name, decimals, address). Use to discover valid trading pairs.", this.getSwapCounterTokens.bind(this), {
182
- token: {
183
- type: "string",
184
- required: true,
185
- description: "Token identifier accepted by the API, e.g. BITCOIN-BTC, LIGHTNING-BTC, STARKNET-STRK, or a token address"
186
- },
187
- side: {
188
- type: "string",
189
- required: true,
190
- description: "Treat the provided token as a source token (INPUT) or destination token (OUTPUT)",
191
- allowedValues: ["INPUT", "OUTPUT"]
192
- }
193
- }),
194
- getSwapLimits: createApiEndpoint<GetSwapLimitsInput, GetSwapLimitsOutput, "GET">("GET", "Get minimum and maximum swap amounts for a source/destination token pair. Returns {input: {min, max?}, output: {min, max?}} where each value is an ApiAmount object with amount (decimal string), rawAmount (base units string), decimals, symbol, and chain.", this.getSwapLimits.bind(this), {
195
- srcToken: { type: "string", required: true, description: "Source token identifier accepted by the API, e.g. BITCOIN-BTC, LIGHTNING-BTC, STARKNET-STRK" },
196
- dstToken: { type: "string", required: true, description: "Destination token identifier accepted by the API, e.g. BITCOIN-BTC, LIGHTNING-BTC, STARKNET-STRK" }
197
- }),
198
- parseAddress: createApiEndpoint<ParseAddressInput, ParseAddressOutput, "GET">("GET", "Parse and validate an address, Lightning invoice, LNURL, or Bitcoin URI. Returns {address, type} and optionally lnurl (ApiLNURL with pay/withdraw details), min/max/amount (as ApiAmount objects).", this.parseAddress.bind(this), {
199
- address: { type: "string", required: true, description: "Address, invoice, LNURL, or URI string to parse" }
200
- }),
201
- getSpendableBalance: createApiEndpoint<GetSpendableBalanceInput, GetSpendableBalanceOutput, "GET">("GET", "Get the spendable balance for a wallet address and token, accounting for chain fees. Returns {balance: ApiAmount, feeRate?} where ApiAmount has amount (decimal string), rawAmount (base units string), decimals, symbol, and chain.", this.getSpendableBalance.bind(this), {
202
- wallet: { type: "string", required: true, description: "Wallet address to query" },
203
- token: { type: "string", required: true, description: "Token identifier accepted by the API, e.g. BITCOIN-BTC, STARKNET-STRK, or a token address" },
204
- targetChain: { type: "string", required: false, description: "Destination smart chain for Bitcoin SPV-vault fee estimation" },
205
- gasDrop: { type: "boolean", required: false, description: "Whether to include gas-drop footprint when estimating Bitcoin SPV-vault spendable balance" },
206
- feeRate: { type: "string", required: false, description: "Manual fee rate override" },
207
- minBitcoinFeeRate: { type: "number", required: false, description: "Minimum Bitcoin fee rate to enforce" },
208
- feeMultiplier: { type: "number", required: false, description: "Multiplier applied to smart-chain native token commit fee estimate" }
209
- }),
210
- getSwapStatus: createApiEndpoint<GetSwapStatusInput, GetSwapStatusOutput, "GET">("GET", "Get the current status and next required action for a swap. Returns swap state, terminal flags (isFinished, isSuccess, isFailed, isExpired), and currentAction (an action object, or null when no action is currently required). For Lightning-to-smart-chain swaps it may also return requiresSecretReveal: true — when set, pass the secret parameter in subsequent getSwapStatus calls so the HTLC can be claimed. Handle each action type: SignPSBT — ask user to sign the Bitcoin PSBT with their wallet, then submit via submitTransaction. SignSmartChainTransaction — ask user to sign with their Solana/Starknet/EVM wallet, then submit via submitTransaction. SendToAddress — show the address and amount to the user, they pay externally, keep polling. Wait — poll again after pollTimeSeconds. Poll repeatedly until isFinished is true.", this.getSwapStatus.bind(this), {
211
- swapId: { type: "string", required: true, description: "The swap identifier" },
212
- secret: { type: "string", required: false, description: "Revealed swap secret pre-image (in hexadecimal format) for lightning network swaps" },
213
- bitcoinAddress: { type: "string", required: false, description: "Bitcoin wallet address to obtain funded PSBT" },
214
- bitcoinPublicKey: { type: "string", required: false, description: "Bitcoin wallet public key (in hexadecimal format) to obtain funded PSBT" },
215
- bitcoinFeeRate: { type: "number", required: false, description: "Fee rate to use when creating a funded PSBT" },
216
- signer: { type: "string", required: false, description: "Alternative different smart chain signer to use for refunds and manual settlement" }
217
- }),
218
- submitTransaction: createApiEndpoint<SubmitTransactionInput, SubmitTransactionOutput, "POST">("POST", "Submit signed transaction(s) for a swap. Call this after the user has signed the transaction returned by getSwapStatus. Returns {txHashes: string[]} with the submitted transaction hashes. After submission, continue polling getSwapStatus.", this.submitTransaction.bind(this), {
219
- swapId: { type: "string", required: true, description: "The swap identifier" },
220
- signedTxs: {
221
- type: "array",
222
- required: true,
223
- description: "Array of signed transaction data",
224
- items: {type: "string", required: true, description: "Single string-serialized & signed transaction"}
225
- }
226
- }),
227
- settleWithLnurl: createApiEndpoint<SettleWithLnurlInput, SettleWithLnurlOutput, "POST">("POST", "Settle a Lightning Network swap using an LNURL-withdraw link. Returns {paymentHash: string} on success.", this.settleWithLnurl.bind(this), {
228
- swapId: { type: "string", required: true, description: "The swap identifier" },
229
- lnurlWithdraw: { type: "string", required: false, description: "LNURL-withdraw link to use to settle the Lightning network swap, if the swap was already created with the LNURL-withdraw link, this is optional" }
230
- })
231
- };
232
- }
233
-
234
- private txSerializer(chainId: string, tx: any): Promise<string> {
235
- const chain = (this.swapper._chains as any)[chainId];
236
- if (chain == null) throw new Error("Unknown chain: " + chainId);
237
- return chain.chainInterface.serializeTx(tx);
238
- }
239
-
240
- async init(): Promise<void> {
241
- await this.swapper.init();
242
- }
243
-
244
- /**
245
- * Should be ran periodically, this synchronizes the swap's state with the on-chain data and also purges
246
- * expired swaps from the persistent storage
247
- */
248
- async sync(): Promise<void> {
249
- await this.swapper._syncSwaps();
250
- }
251
-
252
- /**
253
- * Optionally good to run this periodically, such that any LPs that are dropped off because they are unresponsive
254
- * can be found again.
255
- */
256
- async reloadLps(): Promise<void> {
257
- await this.swapper.intermediaryDiscovery.reloadIntermediaries();
258
- }
259
-
260
- private async createSwap(input: CreateSwapInput): Promise<CreateSwapOutput> {
261
- const exactIn = input.amountType === "EXACT_IN";
262
-
263
- // Build options from input
264
- const options: any = {};
265
- if (input.gasAmount != null) options.gasAmount = input.gasAmount;
266
- if (input.paymentHash != null) options.paymentHash = Buffer.from(input.paymentHash, "hex");
267
- if (input.lightningInvoiceDescription != null) options.description = input.lightningInvoiceDescription;
268
- if (input.lightningInvoiceDescriptionHash != null) options.descriptionHash = Buffer.from(input.lightningInvoiceDescriptionHash, "hex");
269
- if (input.lightningPaymentHTLCTimeout != null) options.expirySeconds = input.lightningPaymentHTLCTimeout;
270
-
271
- // swapper.swap() handles routing based on token types
272
- const swap = await this.swapper.swap(
273
- input.srcToken,
274
- input.dstToken,
275
- input.amount,
276
- exactIn,
277
- input.srcAddress,
278
- input.dstAddress,
279
- Object.keys(options).length > 0 ? options : undefined
280
- );
281
-
282
- const {steps, stateInfo} = await swap.getExecutionStatus({skipBuildingAction: true});
283
-
284
- return createSwapOutputBase(swap, steps, stateInfo);
285
- }
286
-
287
- private validateSwapListInput(input: ListSwapsInput): void {
288
- if (input.chainId != null && !this.swapper.getSmartChains().includes(input.chainId as any)) {
289
- throw new Error("Unknown chainId: " + input.chainId);
290
- }
291
-
292
- if (!this.swapper.Utils.isValidSmartChainAddress(input.signer, input.chainId as any)) {
293
- throw new Error(
294
- input.chainId != null
295
- ? `Invalid ${input.chainId} signer address: ` + input.signer
296
- : `Invalid smart chain signer address: ` + input.signer
297
- );
298
- }
299
- }
300
-
301
- private async createListedSwapOutputs(swaps: ISwap[]): Promise<ListSwapsOutput> {
302
- return Promise.all(
303
- swaps
304
- .filter(swap => swap.getType() !== SwapType.TRUSTED_FROM_BTC)
305
- .map(async swap => {
306
- const {steps, stateInfo} = await swap.getExecutionStatus({skipBuildingAction: true});
307
- return createListSwapOutput(swap, steps, stateInfo);
308
- })
309
- );
310
- }
311
-
312
- private async listSwaps(input: ListSwapsInput): Promise<ListSwapsOutput> {
313
- this.validateSwapListInput(input);
314
-
315
- const swaps = await this.swapper.getAllSwaps(input.chainId as any, input.signer);
316
- return this.createListedSwapOutputs(swaps);
317
- }
318
-
319
- private async listPendingSwaps(input: ListPendingSwapsInput): Promise<ListPendingSwapsOutput> {
320
- this.validateSwapListInput(input);
321
-
322
- const swaps = await this.swapper.getPendingSwaps(input.chainId as any, input.signer);
323
- return this.createListedSwapOutputs(swaps);
324
- }
325
-
326
- private async getSupportedTokens(input: GetSupportedTokensInput): Promise<GetSupportedTokensOutput> {
327
- return this.swapper.getSupportedTokens(parseSwapSide(input.side)).map(toApiToken);
328
- }
329
-
330
- private async getSwapCounterTokens(input: GetSwapCounterTokensInput): Promise<GetSwapCounterTokensOutput> {
331
- const token = this.swapper.getToken(input.token);
332
- return this.swapper.getSwapCounterTokens(token, parseSwapSide(input.side)).map(toApiToken);
333
- }
334
-
335
- private async getSwapLimits(input: GetSwapLimitsInput): Promise<GetSwapLimitsOutput> {
336
- const srcToken = this.swapper.getToken(input.srcToken);
337
- const dstToken = this.swapper.getToken(input.dstToken);
338
- let limits = this.swapper.getSwapLimits(srcToken, dstToken);
339
-
340
- if(dstToken.chainId!=="LIGHTNING") {
341
- if(limits.input.min.rawAmount===1n || limits.output.min.rawAmount===1n) {
342
- // Execute a dummy swap to get the proper limits
343
- try {
344
- await this.swapper.swap(
345
- srcToken, dstToken,
346
- 1n, limits.input.min.rawAmount===1n,
347
- srcToken.chainId==="LIGHTNING" ? undefined : this.swapper.Utils.randomAddress(srcToken.chainId),
348
- this.swapper.Utils.randomAddress(dstToken.chainId)
349
- );
350
- } catch (e) {}
351
- limits = this.swapper.getSwapLimits(srcToken, dstToken);
352
- }
353
- }
354
-
355
- return {
356
- input: {
357
- min: toApiAmount(limits.input.min),
358
- ...(limits.input.max != null ? {max: toApiAmount(limits.input.max)} : {})
359
- },
360
- output: {
361
- min: toApiAmount(limits.output.min),
362
- ...(limits.output.max != null ? {max: toApiAmount(limits.output.max)} : {})
363
- }
364
- };
365
- }
366
-
367
- private async parseAddress(input: ParseAddressInput): Promise<ParseAddressOutput> {
368
- const result = await this.swapper.Utils.parseAddress(input.address);
369
- if(result == null) throw new Error("Invalid address");
370
-
371
- return {
372
- address: result.address,
373
- type: result.type,
374
- ...(result.lnurl != null ? {lnurl: toApiLNURL(result.lnurl, this.swapper)} : {}),
375
- ...(result.min != null ? {min: toApiAmount(result.min)} : {}),
376
- ...(result.max != null ? {max: toApiAmount(result.max)} : {}),
377
- ...(result.amount != null ? {amount: toApiAmount(result.amount)} : {})
378
- };
379
- }
380
-
381
- private async getSpendableBalance(input: GetSpendableBalanceInput): Promise<GetSpendableBalanceOutput> {
382
- const token = this.swapper.getToken(input.token);
383
-
384
- if(token.chainId === "LIGHTNING")
385
- throw new Error("Lightning wallet spendable balance is not supported by this endpoint.");
386
-
387
- if(input.feeRate != null && input.feeMultiplier != null)
388
- throw new Error("`feeMultiplier` cannot be specified alongside the `feeRate` parameter.");
389
-
390
- if(token.chainId === "BITCOIN") {
391
- if(input.targetChain != null && !this.swapper.getSmartChains().includes(input.targetChain as any)) {
392
- throw new Error("Unknown targetChain: " + input.targetChain);
393
- }
394
-
395
- if (!this.swapper.Utils.isValidBitcoinAddress(input.wallet))
396
- throw new Error(`Invalid BITCOIN wallet address: ` + input.wallet);
397
-
398
- let btcFeeRate: number;
399
- if(input.feeRate != null) {
400
- btcFeeRate = parseFloat(input.feeRate);
401
- if(isNaN(btcFeeRate) || btcFeeRate <= 0) throw new Error("Bitcoin `feeRate` must be a valid positive number!");
402
- } else btcFeeRate = await this.swapper._bitcoinRpc.getFeeRate()
403
- if(input.feeMultiplier != null) btcFeeRate *= input.feeMultiplier;
404
-
405
- const {balance, feeRate} = await this.swapper.Utils.getBitcoinSpendableBalance(input.wallet, input.targetChain as any, {
406
- gasDrop: input.gasDrop,
407
- feeRate: btcFeeRate,
408
- minFeeRate: input.minBitcoinFeeRate
409
- });
410
-
411
- return {
412
- balance: toApiAmount(balance),
413
- feeRate
414
- };
415
- }
416
-
417
- if(input.gasDrop === true) throw new Error("`gasDrop` is only supported for Bitcoin balances.");
418
- if(input.minBitcoinFeeRate != null) throw new Error("`minBitcoinFeeRate` is only supported for Bitcoin balances.");
419
-
420
- if (!this.swapper.Utils.isValidSmartChainAddress(input.wallet, token.chainId))
421
- throw new Error(`Invalid ${token.chainId} wallet address: ` + input.wallet);
422
-
423
- const balance = await this.swapper.Utils.getSpendableBalance(input.wallet, token as any, {
424
- feeMultiplier: input.feeMultiplier,
425
- feeRate: input.feeRate
426
- });
427
-
428
- return {
429
- balance: toApiAmount(balance)
430
- };
431
- }
432
-
433
- private async getSwapStatus(input: GetSwapStatusInput): Promise<GetSwapStatusOutput> {
434
- const swap = await this.swapper.getSwapById(input.swapId);
435
- if (swap == null) {
436
- throw new Error("Swap not found: " + input.swapId);
437
- }
438
-
439
- if (input.signer != null && !this.swapper.Utils.isValidSmartChainAddress(input.signer, swap.chainIdentifier)) {
440
- throw new Error(`Invalid ${swap.chainIdentifier} signer address: ` + input.signer);
441
- }
442
-
443
- if (input.secret != null) {
444
- try {
445
- Buffer.from(input.secret, "hex");
446
- } catch (e) {
447
- throw new Error(`Invalid secret passed, has to be a hexadecimal string!`);
448
- }
449
- }
450
-
451
- let bitcoinWallet: MinimalBitcoinWalletInterface | undefined;
452
- if (input.bitcoinAddress != null && input.bitcoinPublicKey != null) {
453
- bitcoinWallet = {
454
- publicKey: input.bitcoinPublicKey,
455
- address: input.bitcoinAddress
456
- };
457
- } else if(input.bitcoinAddress != null || input.bitcoinPublicKey != null) {
458
- throw new Error("When specifying bitcoin wallet you have to pass both `bitcoinAddress` and `bitcoinPublicKey` params!");
459
- }
460
-
461
- if (input.bitcoinFeeRate != null) {
462
- if(isNaN(input.bitcoinFeeRate)) throw new Error("Bitcoin fee rate passed cannot be NaN!");
463
- if(input.bitcoinFeeRate <= 0) throw new Error("Bitcoin fee rate passed cannot be negative or 0!");
464
- }
465
-
466
- if(this.config?.syncOnGetStatus) await swap._sync(true);
467
-
468
- const {steps, stateInfo, currentAction} = await swap.getExecutionStatus({
469
- secret: input.secret,
470
-
471
- bitcoinWallet,
472
- bitcoinFeeRate: input.bitcoinFeeRate,
473
-
474
- manualSettlementSmartChainSigner: input.signer,
475
- refundSmartChainSigner: input.signer
476
- });
477
-
478
- return {
479
- ...createListSwapOutput(swap, steps, stateInfo),
480
-
481
- currentAction: currentAction ? await serializeAction(currentAction, this.txSerializer.bind(this)) : null,
482
- requiresSecretReveal: requiresSecretRevealForApi(swap, stateInfo.state),
483
-
484
- escrow: swap instanceof IEscrowSwap && swap._data!=null ? {
485
- data: swap._data.getEscrowStruct(),
486
- initTxId: swap._commitTxId
487
- } : undefined
488
- };
489
- }
490
-
491
- private async submitTransaction(input: SubmitTransactionInput, abortSignal?: AbortSignal): Promise<SubmitTransactionOutput> {
492
- const swap = await this.swapper.getSwapById(input.swapId);
493
- if (swap == null) {
494
- throw new Error("Swap not found: " + input.swapId);
495
- }
496
-
497
- return {
498
- txHashes: await swap._submitExecutionTransactions(input.signedTxs, abortSignal, undefined, this.config?.idempotentTxSubmission)
499
- }
500
- }
501
-
502
- private async settleWithLnurl(input: SettleWithLnurlInput, abortSignal?: AbortSignal): Promise<SettleWithLnurlOutput> {
503
- const swap = await this.swapper.getSwapById(input.swapId);
504
- if (swap == null) throw new Error("Swap not found: " + input.swapId);
505
-
506
- if (swap instanceof FromBTCLNAutoSwap) {
507
- if(swap._state!==FromBTCLNAutoSwapState.PR_CREATED)
508
- throw new Error("Invalid swap state, must be in PR_CREATED state!");
509
- } else if (swap instanceof FromBTCLNSwap) {
510
- if(swap._state!==FromBTCLNSwapState.PR_CREATED)
511
- throw new Error("Invalid swap state, must be in PR_CREATED state!");
512
- } else {
513
- throw new Error("Endpoint only supports swaps from Lightning");
514
- }
515
-
516
- if (!swap.isLNURL()) {
517
- if (input.lnurlWithdraw==null)
518
- throw new Error("The swap is not configured to use LNURL, please pass the `lnurlWithdraw` parameter!");
519
-
520
- if (!this.swapper.Utils.isValidLNURL(input.lnurlWithdraw))
521
- throw new Error("Invalid LNURL-withdraw link provided: " + input.lnurlWithdraw);
522
-
523
- await swap.settleWithLNURLWithdraw(input.lnurlWithdraw);
524
- } else {
525
- if (input.lnurlWithdraw!=null)
526
- throw new Error("The swap is already configured with an LNURL link, don't pass the `lnurlWithdraw` parameter!");
527
- }
528
-
529
- let success: boolean;
530
- if (swap instanceof FromBTCLNAutoSwap) {
531
- // For non-legacy swap, we don't need to wait till the swap advances all the way to committed state
532
- success = await swap._waitForLpPaymentReceived(2, abortSignal);
533
- } else {
534
- // For legacy swap waitForPayment waits just for the swap to transition into PR_PAID
535
- success = await swap.waitForPayment(undefined, 2, abortSignal);
536
- }
537
-
538
- if(!success) throw new Error("Failed to settle the swap with the LNURL-withdraw link!");
539
-
540
- return {
541
- paymentHash: swap.getInputTxId()!
542
- };
543
- }
544
-
545
- }
1
+ import {MultiChain, Swapper} from "../swapper/Swapper";
2
+ import {ApiEndpoint, createApiEndpoint, toApiAmount, toApiLNURL, toApiToken} from "./ApiTypes";
3
+ import {ISwap} from "../swaps/ISwap";
4
+ import {serializeAction} from "./SerializedAction";
5
+ import {FeeType} from "../enums/FeeType";
6
+ import {SwapSide} from "../enums/SwapSide";
7
+ import {SwapType} from "../enums/SwapType";
8
+ import {MinimalBitcoinWalletInterface} from "../types/wallets/MinimalBitcoinWalletInterface";
9
+ import {FromBTCLNSwap, FromBTCLNSwapState} from "../swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap";
10
+ import {FromBTCLNAutoSwap, FromBTCLNAutoSwapState} from "../swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap";
11
+ import {
12
+ CreateSwapInput,
13
+ CreateSwapOutput,
14
+ GetSpendableBalanceInput,
15
+ GetSpendableBalanceOutput,
16
+ GetSupportedTokensInput,
17
+ GetSupportedTokensOutput,
18
+ GetSwapCounterTokensInput,
19
+ GetSwapCounterTokensOutput,
20
+ GetSwapLimitsInput,
21
+ GetSwapLimitsOutput,
22
+ GetSwapStatusInput,
23
+ GetSwapStatusOutput,
24
+ ListPendingSwapsInput,
25
+ ListPendingSwapsOutput,
26
+ ListSwapOutput,
27
+ ListSwapsInput,
28
+ ListSwapsOutput,
29
+ ParseAddressInput,
30
+ ParseAddressOutput,
31
+ SettleWithLnurlInput,
32
+ SettleWithLnurlOutput,
33
+ SubmitTransactionInput,
34
+ SubmitTransactionOutput,
35
+ SwapOutputBase
36
+ } from "./ApiEndpoints";
37
+ import {SwapExecutionStep} from "../types/SwapExecutionStep";
38
+ import {SwapStateInfo} from "../types/SwapStateInfo";
39
+ import {IEscrowSwap} from "../swaps/escrow_swaps/IEscrowSwap";
40
+ import {ToBTCLNSwap} from "../swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap";
41
+
42
+ function requiresSecretRevealForApi(swap: ISwap, state: number): boolean | undefined {
43
+ if(swap instanceof FromBTCLNSwap) {
44
+ if(swap.hasSecretPreimage()) return false;
45
+ return state===FromBTCLNSwapState.PR_PAID || state===FromBTCLNSwapState.CLAIM_COMMITED;
46
+ }
47
+ if(swap instanceof FromBTCLNAutoSwap) {
48
+ if(swap.hasSecretPreimage()) return false;
49
+ return state===FromBTCLNAutoSwapState.CLAIM_COMMITED;
50
+ }
51
+ }
52
+
53
+ function createSwapOutputBase(
54
+ swap: ISwap,
55
+ steps: SwapExecutionStep[],
56
+ stateInfo: SwapStateInfo<number>
57
+ ): SwapOutputBase {
58
+ const input = swap.getInput();
59
+ const output = swap.getOutput();
60
+ const feeBreakdown = swap.getFeeBreakdown();
61
+
62
+ // Build fees from breakdown
63
+ const swapFeeEntry = feeBreakdown.find(f => f.type === FeeType.SWAP);
64
+ const networkFeeEntry = feeBreakdown.find(f => f.type === FeeType.NETWORK_OUTPUT);
65
+
66
+ return {
67
+ swapId: swap.getId(),
68
+ swapType: SwapType[swap.getType()],
69
+
70
+ state: {
71
+ number: stateInfo.state,
72
+ name: stateInfo.name,
73
+ description: stateInfo.description
74
+ },
75
+
76
+ quote: {
77
+ inputAmount: toApiAmount(input),
78
+ outputAmount: toApiAmount(output),
79
+ fees: {
80
+ swap: swapFeeEntry
81
+ ? toApiAmount(swapFeeEntry.fee.amountInSrcToken)
82
+ : { amount: "0", rawAmount: "0", decimals: 0, symbol: "", chain: "" },
83
+ ...(networkFeeEntry ? {
84
+ networkOutput: toApiAmount(networkFeeEntry.fee.amountInSrcToken)
85
+ } : {})
86
+ },
87
+ expiry: swap.getQuoteExpiry(),
88
+ outputAddress: swap.getOutputAddress()!
89
+ },
90
+
91
+ createdAt: swap.createdAt,
92
+
93
+ steps,
94
+
95
+ ...(swap instanceof ToBTCLNSwap && swap.isLNURL() ? {
96
+ lnurl: {
97
+ pay: swap.getLNURL()!,
98
+ successAction: swap.getSuccessAction() ?? undefined
99
+ }
100
+ } : (swap instanceof FromBTCLNSwap || swap instanceof FromBTCLNAutoSwap) && swap.isLNURL() ? {
101
+ lnurl: {
102
+ withdraw: swap.getLNURL()!,
103
+ }
104
+ } : {})
105
+ };
106
+ }
107
+
108
+ function createListSwapOutput(
109
+ swap: ISwap,
110
+ steps: SwapExecutionStep[],
111
+ stateInfo: SwapStateInfo<number>
112
+ ): ListSwapOutput {
113
+ return {
114
+ ...createSwapOutputBase(swap, steps, stateInfo),
115
+
116
+ isFinished: swap.isFinished(),
117
+ isSuccess: swap.isSuccessful(),
118
+ isFailed: swap.isFailed(),
119
+ isExpired: swap.isQuoteExpired()
120
+ };
121
+ }
122
+
123
+ function parseSwapSide(side: "INPUT" | "OUTPUT"): SwapSide {
124
+ return side === "INPUT" ? SwapSide.INPUT : SwapSide.OUTPUT;
125
+ }
126
+
127
+ export type SwapperApiConfig = {
128
+ syncOnGetStatus?: boolean,
129
+ idempotentTxSubmission?: boolean
130
+ };
131
+
132
+ export class SwapperApi<T extends MultiChain> {
133
+
134
+ readonly endpoints: {
135
+ createSwap: ApiEndpoint<CreateSwapInput, CreateSwapOutput, "POST">;
136
+ listSwaps: ApiEndpoint<ListSwapsInput, ListSwapsOutput, "GET">;
137
+ listPendingSwaps: ApiEndpoint<ListPendingSwapsInput, ListPendingSwapsOutput, "GET">;
138
+ getSupportedTokens: ApiEndpoint<GetSupportedTokensInput, GetSupportedTokensOutput, "GET">;
139
+ getSwapCounterTokens: ApiEndpoint<GetSwapCounterTokensInput, GetSwapCounterTokensOutput, "GET">;
140
+ getSwapLimits: ApiEndpoint<GetSwapLimitsInput, GetSwapLimitsOutput, "GET">;
141
+ parseAddress: ApiEndpoint<ParseAddressInput, ParseAddressOutput, "GET">;
142
+ getSpendableBalance: ApiEndpoint<GetSpendableBalanceInput, GetSpendableBalanceOutput, "GET">;
143
+ getSwapStatus: ApiEndpoint<GetSwapStatusInput, GetSwapStatusOutput, "GET">;
144
+ submitTransaction: ApiEndpoint<SubmitTransactionInput, SubmitTransactionOutput, "POST">;
145
+ settleWithLnurl: ApiEndpoint<SettleWithLnurlInput, SettleWithLnurlOutput, "POST">;
146
+ };
147
+
148
+ constructor(private swapper: Swapper<T>, private readonly config?: SwapperApiConfig) {
149
+ this.config ??= {};
150
+ this.config.syncOnGetStatus ??= true;
151
+ this.endpoints = {
152
+ createSwap: createApiEndpoint<CreateSwapInput, CreateSwapOutput, "POST">("POST", "Create a new cross-chain atomic swap. Returns a swap object with swapId, swapType, state, createdAt, quote (with inputAmount and outputAmount as ApiAmount objects each having amount/rawAmount/decimals/symbol/chain, a fees breakdown {swap, networkOutput?} of ApiAmount values, expiry, and outputAddress), a steps array, and optional lnurl. After creation, poll getSwapStatus periodically to get the next required action.", this.createSwap.bind(this), {
153
+ srcToken: { type: "string", required: true, description: "Source token ticker (e.g. 'BITCOIN-BTC', 'LIGHTNING-BTC', 'STARKNET-STRK', 'SOLANA-SOL')" },
154
+ dstToken: { type: "string", required: true, description: "Destination token ticker" },
155
+ amount: { type: "bigint", required: true, description: "Amount in base units as an integer" },
156
+ amountType: { type: "string", required: true, description: "EXACT_IN or EXACT_OUT", allowedValues: ["EXACT_IN", "EXACT_OUT"] },
157
+ srcAddress: { type: "string", required: false, description: "Source address (only required for Smart chain -> BTC/Lightning swaps)" },
158
+ dstAddress: { type: "string", required: true, description: "Destination address" },
159
+ gasAmount: { type: "bigint", required: false, description: "Gas token amount to receive on destination chain, in base units" },
160
+ paymentHash: { type: "string", required: false, description: "Custom payment hash for Lightning swaps" },
161
+ lightningInvoiceDescription: { type: "string", required: false, description: "Description for Lightning invoice" },
162
+ lightningInvoiceDescriptionHash: { type: "string", required: false, description: "Description hash for Lightning invoice (hex)" },
163
+ lightningPaymentHTLCTimeout: { type: "number", required: false, description: "Custom expiry time in seconds" }
164
+ }),
165
+ listSwaps: createApiEndpoint<ListSwapsInput, ListSwapsOutput, "GET">("GET", "List all swaps for a given signer address. Returns an array of swap objects, each with swapId, swapType, state, quote, steps, and terminal state flags (isFinished, isSuccess, isFailed, isExpired). Optionally filter by smart chain.", this.listSwaps.bind(this), {
166
+ signer: { type: "string", required: true, description: "Smart chain signer address to filter swaps for" },
167
+ chainId: { type: "string", required: false, description: "Optional smart chain identifier to filter swaps" }
168
+ }),
169
+ listPendingSwaps: createApiEndpoint<ListPendingSwapsInput, ListPendingSwapsOutput, "GET">("GET", "List swaps that require user action for a given signer address. Returns an array of swap objects with the same structure as listSwaps.", this.listPendingSwaps.bind(this), {
170
+ signer: { type: "string", required: true, description: "Smart chain signer address to filter pending swaps for" },
171
+ chainId: { type: "string", required: false, description: "Optional smart chain identifier to filter pending swaps" }
172
+ }),
173
+ getSupportedTokens: createApiEndpoint<GetSupportedTokensInput, GetSupportedTokensOutput, "GET">("GET", "List all tokens available as swap input or output. Returns an array of ApiToken objects, each with id (e.g. BITCOIN-BTC, LIGHTNING-BTC, STARKNET-STRK), chainId, ticker, name, decimals, and address.", this.getSupportedTokens.bind(this), {
174
+ side: {
175
+ type: "string",
176
+ required: true,
177
+ description: "Whether to list valid source tokens (INPUT) or destination tokens (OUTPUT)",
178
+ allowedValues: ["INPUT", "OUTPUT"]
179
+ }
180
+ }),
181
+ getSwapCounterTokens: createApiEndpoint<GetSwapCounterTokensInput, GetSwapCounterTokensOutput, "GET">("GET", "Get tokens that can be swapped against a given token. Returns an array of ApiToken objects (id, chainId, ticker, name, decimals, address). Use to discover valid trading pairs.", this.getSwapCounterTokens.bind(this), {
182
+ token: {
183
+ type: "string",
184
+ required: true,
185
+ description: "Token identifier accepted by the API, e.g. BITCOIN-BTC, LIGHTNING-BTC, STARKNET-STRK, or a token address"
186
+ },
187
+ side: {
188
+ type: "string",
189
+ required: true,
190
+ description: "Treat the provided token as a source token (INPUT) or destination token (OUTPUT)",
191
+ allowedValues: ["INPUT", "OUTPUT"]
192
+ }
193
+ }),
194
+ getSwapLimits: createApiEndpoint<GetSwapLimitsInput, GetSwapLimitsOutput, "GET">("GET", "Get minimum and maximum swap amounts for a source/destination token pair. Returns {input: {min, max?}, output: {min, max?}} where each value is an ApiAmount object with amount (decimal string), rawAmount (base units string), decimals, symbol, and chain.", this.getSwapLimits.bind(this), {
195
+ srcToken: { type: "string", required: true, description: "Source token identifier accepted by the API, e.g. BITCOIN-BTC, LIGHTNING-BTC, STARKNET-STRK" },
196
+ dstToken: { type: "string", required: true, description: "Destination token identifier accepted by the API, e.g. BITCOIN-BTC, LIGHTNING-BTC, STARKNET-STRK" }
197
+ }),
198
+ parseAddress: createApiEndpoint<ParseAddressInput, ParseAddressOutput, "GET">("GET", "Parse and validate an address, Lightning invoice, LNURL, or Bitcoin URI. Returns {address, type} and optionally lnurl (ApiLNURL with pay/withdraw details), min/max/amount (as ApiAmount objects).", this.parseAddress.bind(this), {
199
+ address: { type: "string", required: true, description: "Address, invoice, LNURL, or URI string to parse" }
200
+ }),
201
+ getSpendableBalance: createApiEndpoint<GetSpendableBalanceInput, GetSpendableBalanceOutput, "GET">("GET", "Get the spendable balance for a wallet address and token, accounting for chain fees. Returns {balance: ApiAmount, feeRate?} where ApiAmount has amount (decimal string), rawAmount (base units string), decimals, symbol, and chain.", this.getSpendableBalance.bind(this), {
202
+ wallet: { type: "string", required: true, description: "Wallet address to query" },
203
+ token: { type: "string", required: true, description: "Token identifier accepted by the API, e.g. BITCOIN-BTC, STARKNET-STRK, or a token address" },
204
+ targetChain: { type: "string", required: false, description: "Destination smart chain for Bitcoin SPV-vault fee estimation" },
205
+ gasDrop: { type: "boolean", required: false, description: "Whether to include gas-drop footprint when estimating Bitcoin SPV-vault spendable balance" },
206
+ feeRate: { type: "string", required: false, description: "Manual fee rate override" },
207
+ minBitcoinFeeRate: { type: "number", required: false, description: "Minimum Bitcoin fee rate to enforce" },
208
+ feeMultiplier: { type: "number", required: false, description: "Multiplier applied to smart-chain native token commit fee estimate" }
209
+ }),
210
+ getSwapStatus: createApiEndpoint<GetSwapStatusInput, GetSwapStatusOutput, "GET">("GET", "Get the current status and next required action for a swap. Returns swap state, terminal flags (isFinished, isSuccess, isFailed, isExpired), and currentAction (an action object, or null when no action is currently required). For Lightning-to-smart-chain swaps it may also return requiresSecretReveal: true — when set, pass the secret parameter in subsequent getSwapStatus calls so the HTLC can be claimed. Handle each action type: SignPSBT — ask user to sign the Bitcoin PSBT with their wallet, then submit via submitTransaction. SignSmartChainTransaction — ask user to sign with their Solana/Starknet/EVM wallet, then submit via submitTransaction. SendToAddress — show the address and amount to the user, they pay externally, keep polling. Wait — poll again after pollTimeSeconds. Poll repeatedly until isFinished is true.", this.getSwapStatus.bind(this), {
211
+ swapId: { type: "string", required: true, description: "The swap identifier" },
212
+ secret: { type: "string", required: false, description: "Revealed swap secret pre-image (in hexadecimal format) for lightning network swaps" },
213
+ bitcoinAddress: { type: "string", required: false, description: "Bitcoin wallet address to obtain funded PSBT" },
214
+ bitcoinPublicKey: { type: "string", required: false, description: "Bitcoin wallet public key (in hexadecimal format) to obtain funded PSBT" },
215
+ bitcoinFeeRate: { type: "number", required: false, description: "Fee rate to use when creating a funded PSBT" },
216
+ signer: { type: "string", required: false, description: "Alternative different smart chain signer to use for refunds and manual settlement" }
217
+ }),
218
+ submitTransaction: createApiEndpoint<SubmitTransactionInput, SubmitTransactionOutput, "POST">("POST", "Submit signed transaction(s) for a swap. Call this after the user has signed the transaction returned by getSwapStatus. Returns {txHashes: string[]} with the submitted transaction hashes. After submission, continue polling getSwapStatus.", this.submitTransaction.bind(this), {
219
+ swapId: { type: "string", required: true, description: "The swap identifier" },
220
+ signedTxs: {
221
+ type: "array",
222
+ required: true,
223
+ description: "Array of signed transaction data",
224
+ items: {type: "string", required: true, description: "Single string-serialized & signed transaction"}
225
+ }
226
+ }),
227
+ settleWithLnurl: createApiEndpoint<SettleWithLnurlInput, SettleWithLnurlOutput, "POST">("POST", "Settle a Lightning Network swap using an LNURL-withdraw link. Returns {paymentHash: string} on success.", this.settleWithLnurl.bind(this), {
228
+ swapId: { type: "string", required: true, description: "The swap identifier" },
229
+ lnurlWithdraw: { type: "string", required: false, description: "LNURL-withdraw link to use to settle the Lightning network swap, if the swap was already created with the LNURL-withdraw link, this is optional" }
230
+ })
231
+ };
232
+ }
233
+
234
+ private txSerializer(chainId: string, tx: any): Promise<string> {
235
+ const chain = (this.swapper._chains as any)[chainId];
236
+ if (chain == null) throw new Error("Unknown chain: " + chainId);
237
+ return chain.chainInterface.serializeTx(tx);
238
+ }
239
+
240
+ async init(): Promise<void> {
241
+ await this.swapper.init();
242
+ }
243
+
244
+ /**
245
+ * Should be ran periodically, this synchronizes the swap's state with the on-chain data and also purges
246
+ * expired swaps from the persistent storage
247
+ */
248
+ async sync(): Promise<void> {
249
+ await this.swapper._syncSwaps();
250
+ }
251
+
252
+ /**
253
+ * Optionally good to run this periodically, such that any LPs that are dropped off because they are unresponsive
254
+ * can be found again.
255
+ */
256
+ async reloadLps(): Promise<void> {
257
+ await this.swapper.intermediaryDiscovery.reloadIntermediaries();
258
+ }
259
+
260
+ private async createSwap(input: CreateSwapInput): Promise<CreateSwapOutput> {
261
+ const exactIn = input.amountType === "EXACT_IN";
262
+
263
+ // Build options from input
264
+ const options: any = {};
265
+ if (input.gasAmount != null) options.gasAmount = input.gasAmount;
266
+ if (input.paymentHash != null) options.paymentHash = Buffer.from(input.paymentHash, "hex");
267
+ if (input.lightningInvoiceDescription != null) options.description = input.lightningInvoiceDescription;
268
+ if (input.lightningInvoiceDescriptionHash != null) options.descriptionHash = Buffer.from(input.lightningInvoiceDescriptionHash, "hex");
269
+ if (input.lightningPaymentHTLCTimeout != null) options.expirySeconds = input.lightningPaymentHTLCTimeout;
270
+
271
+ // swapper.swap() handles routing based on token types
272
+ const swap = await this.swapper.swap(
273
+ input.srcToken,
274
+ input.dstToken,
275
+ input.amount,
276
+ exactIn,
277
+ input.srcAddress,
278
+ input.dstAddress,
279
+ Object.keys(options).length > 0 ? options : undefined
280
+ );
281
+
282
+ const {steps, stateInfo} = await swap.getExecutionStatus({skipBuildingAction: true});
283
+
284
+ return createSwapOutputBase(swap, steps, stateInfo);
285
+ }
286
+
287
+ private validateSwapListInput(input: ListSwapsInput): void {
288
+ if (input.chainId != null && !this.swapper.getSmartChains().includes(input.chainId as any)) {
289
+ throw new Error("Unknown chainId: " + input.chainId);
290
+ }
291
+
292
+ if (!this.swapper.Utils.isValidSmartChainAddress(input.signer, input.chainId as any)) {
293
+ throw new Error(
294
+ input.chainId != null
295
+ ? `Invalid ${input.chainId} signer address: ` + input.signer
296
+ : `Invalid smart chain signer address: ` + input.signer
297
+ );
298
+ }
299
+ }
300
+
301
+ private async createListedSwapOutputs(swaps: ISwap[]): Promise<ListSwapsOutput> {
302
+ return Promise.all(
303
+ swaps
304
+ .filter(swap => swap.getType() !== SwapType.TRUSTED_FROM_BTC)
305
+ .map(async swap => {
306
+ const {steps, stateInfo} = await swap.getExecutionStatus({skipBuildingAction: true});
307
+ return createListSwapOutput(swap, steps, stateInfo);
308
+ })
309
+ );
310
+ }
311
+
312
+ private async listSwaps(input: ListSwapsInput): Promise<ListSwapsOutput> {
313
+ this.validateSwapListInput(input);
314
+
315
+ const swaps = await this.swapper.getAllSwaps(input.chainId as any, input.signer);
316
+ return this.createListedSwapOutputs(swaps);
317
+ }
318
+
319
+ private async listPendingSwaps(input: ListPendingSwapsInput): Promise<ListPendingSwapsOutput> {
320
+ this.validateSwapListInput(input);
321
+
322
+ const swaps = await this.swapper.getPendingSwaps(input.chainId as any, input.signer);
323
+ return this.createListedSwapOutputs(swaps);
324
+ }
325
+
326
+ private async getSupportedTokens(input: GetSupportedTokensInput): Promise<GetSupportedTokensOutput> {
327
+ return this.swapper.getSupportedTokens(parseSwapSide(input.side)).map(toApiToken);
328
+ }
329
+
330
+ private async getSwapCounterTokens(input: GetSwapCounterTokensInput): Promise<GetSwapCounterTokensOutput> {
331
+ const token = this.swapper.getToken(input.token);
332
+ return this.swapper.getSwapCounterTokens(token, parseSwapSide(input.side)).map(toApiToken);
333
+ }
334
+
335
+ private async getSwapLimits(input: GetSwapLimitsInput): Promise<GetSwapLimitsOutput> {
336
+ const srcToken = this.swapper.getToken(input.srcToken);
337
+ const dstToken = this.swapper.getToken(input.dstToken);
338
+ let limits = this.swapper.getSwapLimits(srcToken, dstToken);
339
+
340
+ if(dstToken.chainId!=="LIGHTNING") {
341
+ if(limits.input.min.rawAmount===1n || limits.output.min.rawAmount===1n) {
342
+ // Execute a dummy swap to get the proper limits
343
+ try {
344
+ await this.swapper.swap(
345
+ srcToken, dstToken,
346
+ 1n, limits.input.min.rawAmount===1n,
347
+ srcToken.chainId==="LIGHTNING" ? undefined : this.swapper.Utils.randomAddress(srcToken.chainId),
348
+ this.swapper.Utils.randomAddress(dstToken.chainId)
349
+ );
350
+ } catch (e) {}
351
+ limits = this.swapper.getSwapLimits(srcToken, dstToken);
352
+ }
353
+ }
354
+
355
+ return {
356
+ input: {
357
+ min: toApiAmount(limits.input.min),
358
+ ...(limits.input.max != null ? {max: toApiAmount(limits.input.max)} : {})
359
+ },
360
+ output: {
361
+ min: toApiAmount(limits.output.min),
362
+ ...(limits.output.max != null ? {max: toApiAmount(limits.output.max)} : {})
363
+ }
364
+ };
365
+ }
366
+
367
+ private async parseAddress(input: ParseAddressInput): Promise<ParseAddressOutput> {
368
+ const result = await this.swapper.Utils.parseAddress(input.address);
369
+ if(result == null) throw new Error("Invalid address");
370
+
371
+ return {
372
+ address: result.address,
373
+ type: result.type,
374
+ ...(result.lnurl != null ? {lnurl: toApiLNURL(result.lnurl, this.swapper)} : {}),
375
+ ...(result.min != null ? {min: toApiAmount(result.min)} : {}),
376
+ ...(result.max != null ? {max: toApiAmount(result.max)} : {}),
377
+ ...(result.amount != null ? {amount: toApiAmount(result.amount)} : {})
378
+ };
379
+ }
380
+
381
+ private async getSpendableBalance(input: GetSpendableBalanceInput): Promise<GetSpendableBalanceOutput> {
382
+ const token = this.swapper.getToken(input.token);
383
+
384
+ if(token.chainId === "LIGHTNING")
385
+ throw new Error("Lightning wallet spendable balance is not supported by this endpoint.");
386
+
387
+ if(input.feeRate != null && input.feeMultiplier != null)
388
+ throw new Error("`feeMultiplier` cannot be specified alongside the `feeRate` parameter.");
389
+
390
+ if(token.chainId === "BITCOIN") {
391
+ if(input.targetChain != null && !this.swapper.getSmartChains().includes(input.targetChain as any)) {
392
+ throw new Error("Unknown targetChain: " + input.targetChain);
393
+ }
394
+
395
+ if (!this.swapper.Utils.isValidBitcoinAddress(input.wallet))
396
+ throw new Error(`Invalid BITCOIN wallet address: ` + input.wallet);
397
+
398
+ let btcFeeRate: number;
399
+ if(input.feeRate != null) {
400
+ btcFeeRate = parseFloat(input.feeRate);
401
+ if(isNaN(btcFeeRate) || btcFeeRate <= 0) throw new Error("Bitcoin `feeRate` must be a valid positive number!");
402
+ } else btcFeeRate = await this.swapper._bitcoinRpc.getFeeRate()
403
+ if(input.feeMultiplier != null) btcFeeRate *= input.feeMultiplier;
404
+
405
+ const {balance, feeRate} = await this.swapper.Utils.getBitcoinSpendableBalance(input.wallet, input.targetChain as any, {
406
+ gasDrop: input.gasDrop,
407
+ feeRate: btcFeeRate,
408
+ minFeeRate: input.minBitcoinFeeRate
409
+ });
410
+
411
+ return {
412
+ balance: toApiAmount(balance),
413
+ feeRate
414
+ };
415
+ }
416
+
417
+ if(input.gasDrop === true) throw new Error("`gasDrop` is only supported for Bitcoin balances.");
418
+ if(input.minBitcoinFeeRate != null) throw new Error("`minBitcoinFeeRate` is only supported for Bitcoin balances.");
419
+
420
+ if (!this.swapper.Utils.isValidSmartChainAddress(input.wallet, token.chainId))
421
+ throw new Error(`Invalid ${token.chainId} wallet address: ` + input.wallet);
422
+
423
+ const balance = await this.swapper.Utils.getSpendableBalance(input.wallet, token as any, {
424
+ feeMultiplier: input.feeMultiplier,
425
+ feeRate: input.feeRate
426
+ });
427
+
428
+ return {
429
+ balance: toApiAmount(balance)
430
+ };
431
+ }
432
+
433
+ private async getSwapStatus(input: GetSwapStatusInput): Promise<GetSwapStatusOutput> {
434
+ const swap = await this.swapper.getSwapById(input.swapId);
435
+ if (swap == null) {
436
+ throw new Error("Swap not found: " + input.swapId);
437
+ }
438
+
439
+ if (input.signer != null && !this.swapper.Utils.isValidSmartChainAddress(input.signer, swap.chainIdentifier)) {
440
+ throw new Error(`Invalid ${swap.chainIdentifier} signer address: ` + input.signer);
441
+ }
442
+
443
+ if (input.secret != null) {
444
+ try {
445
+ Buffer.from(input.secret, "hex");
446
+ } catch (e) {
447
+ throw new Error(`Invalid secret passed, has to be a hexadecimal string!`);
448
+ }
449
+ }
450
+
451
+ let bitcoinWallet: MinimalBitcoinWalletInterface | undefined;
452
+ if (input.bitcoinAddress != null && input.bitcoinPublicKey != null) {
453
+ bitcoinWallet = {
454
+ publicKey: input.bitcoinPublicKey,
455
+ address: input.bitcoinAddress
456
+ };
457
+ } else if(input.bitcoinAddress != null || input.bitcoinPublicKey != null) {
458
+ throw new Error("When specifying bitcoin wallet you have to pass both `bitcoinAddress` and `bitcoinPublicKey` params!");
459
+ }
460
+
461
+ if (input.bitcoinFeeRate != null) {
462
+ if(isNaN(input.bitcoinFeeRate)) throw new Error("Bitcoin fee rate passed cannot be NaN!");
463
+ if(input.bitcoinFeeRate <= 0) throw new Error("Bitcoin fee rate passed cannot be negative or 0!");
464
+ }
465
+
466
+ if(this.config?.syncOnGetStatus) await swap._sync(true);
467
+
468
+ const {steps, stateInfo, currentAction} = await swap.getExecutionStatus({
469
+ secret: input.secret,
470
+
471
+ bitcoinWallet,
472
+ bitcoinFeeRate: input.bitcoinFeeRate,
473
+
474
+ manualSettlementSmartChainSigner: input.signer,
475
+ refundSmartChainSigner: input.signer
476
+ });
477
+
478
+ return {
479
+ ...createListSwapOutput(swap, steps, stateInfo),
480
+
481
+ currentAction: currentAction ? await serializeAction(currentAction, this.txSerializer.bind(this)) : null,
482
+ requiresSecretReveal: requiresSecretRevealForApi(swap, stateInfo.state),
483
+
484
+ escrow: swap instanceof IEscrowSwap && swap._data!=null ? {
485
+ data: swap._data.getEscrowStruct(),
486
+ initTxId: swap._commitTxId
487
+ } : undefined
488
+ };
489
+ }
490
+
491
+ private async submitTransaction(input: SubmitTransactionInput, abortSignal?: AbortSignal): Promise<SubmitTransactionOutput> {
492
+ const swap = await this.swapper.getSwapById(input.swapId);
493
+ if (swap == null) {
494
+ throw new Error("Swap not found: " + input.swapId);
495
+ }
496
+
497
+ return {
498
+ txHashes: await swap._submitExecutionTransactions(input.signedTxs, abortSignal, undefined, this.config?.idempotentTxSubmission)
499
+ }
500
+ }
501
+
502
+ private async settleWithLnurl(input: SettleWithLnurlInput, abortSignal?: AbortSignal): Promise<SettleWithLnurlOutput> {
503
+ const swap = await this.swapper.getSwapById(input.swapId);
504
+ if (swap == null) throw new Error("Swap not found: " + input.swapId);
505
+
506
+ if (swap instanceof FromBTCLNAutoSwap) {
507
+ if(swap._state!==FromBTCLNAutoSwapState.PR_CREATED)
508
+ throw new Error("Invalid swap state, must be in PR_CREATED state!");
509
+ } else if (swap instanceof FromBTCLNSwap) {
510
+ if(swap._state!==FromBTCLNSwapState.PR_CREATED)
511
+ throw new Error("Invalid swap state, must be in PR_CREATED state!");
512
+ } else {
513
+ throw new Error("Endpoint only supports swaps from Lightning");
514
+ }
515
+
516
+ if (!swap.isLNURL()) {
517
+ if (input.lnurlWithdraw==null)
518
+ throw new Error("The swap is not configured to use LNURL, please pass the `lnurlWithdraw` parameter!");
519
+
520
+ if (!this.swapper.Utils.isValidLNURL(input.lnurlWithdraw))
521
+ throw new Error("Invalid LNURL-withdraw link provided: " + input.lnurlWithdraw);
522
+
523
+ await swap.settleWithLNURLWithdraw(input.lnurlWithdraw);
524
+ } else {
525
+ if (input.lnurlWithdraw!=null)
526
+ throw new Error("The swap is already configured with an LNURL link, don't pass the `lnurlWithdraw` parameter!");
527
+ }
528
+
529
+ let success: boolean;
530
+ if (swap instanceof FromBTCLNAutoSwap) {
531
+ // For non-legacy swap, we don't need to wait till the swap advances all the way to committed state
532
+ success = await swap._waitForLpPaymentReceived(2, abortSignal);
533
+ } else {
534
+ // For legacy swap waitForPayment waits just for the swap to transition into PR_PAID
535
+ success = await swap.waitForPayment(undefined, 2, abortSignal);
536
+ }
537
+
538
+ if(!success) throw new Error("Failed to settle the swap with the LNURL-withdraw link!");
539
+
540
+ return {
541
+ paymentHash: swap.getInputTxId()!
542
+ };
543
+ }
544
+
545
+ }