@atomiqlabs/sdk 8.8.3 → 8.8.4

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 (339) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +1760 -1760
  3. package/dist/SmartChainAssets.d.ts +181 -181
  4. package/dist/SmartChainAssets.js +181 -181
  5. package/dist/bitcoin/coinselect2/accumulative.d.ts +7 -7
  6. package/dist/bitcoin/coinselect2/accumulative.js +52 -52
  7. package/dist/bitcoin/coinselect2/blackjack.d.ts +7 -7
  8. package/dist/bitcoin/coinselect2/blackjack.js +38 -38
  9. package/dist/bitcoin/coinselect2/index.d.ts +20 -20
  10. package/dist/bitcoin/coinselect2/index.js +69 -69
  11. package/dist/bitcoin/coinselect2/utils.d.ts +82 -82
  12. package/dist/bitcoin/coinselect2/utils.js +158 -158
  13. package/dist/bitcoin/wallet/BitcoinWallet.d.ts +113 -113
  14. package/dist/bitcoin/wallet/BitcoinWallet.js +335 -335
  15. package/dist/bitcoin/wallet/IBitcoinWallet.d.ts +116 -116
  16. package/dist/bitcoin/wallet/IBitcoinWallet.js +21 -21
  17. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.d.ts +106 -106
  18. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.js +196 -196
  19. package/dist/enums/FeeType.d.ts +15 -15
  20. package/dist/enums/FeeType.js +19 -19
  21. package/dist/enums/SwapAmountType.d.ts +15 -15
  22. package/dist/enums/SwapAmountType.js +19 -19
  23. package/dist/enums/SwapDirection.d.ts +15 -15
  24. package/dist/enums/SwapDirection.js +19 -19
  25. package/dist/enums/SwapSide.d.ts +15 -15
  26. package/dist/enums/SwapSide.js +19 -19
  27. package/dist/enums/SwapType.d.ts +75 -75
  28. package/dist/enums/SwapType.js +79 -79
  29. package/dist/errors/IntermediaryError.d.ts +13 -13
  30. package/dist/errors/IntermediaryError.js +27 -27
  31. package/dist/errors/RequestError.d.ts +32 -32
  32. package/dist/errors/RequestError.js +54 -54
  33. package/dist/errors/UserError.d.ts +8 -8
  34. package/dist/errors/UserError.js +16 -16
  35. package/dist/events/UnifiedSwapEventListener.d.ts +23 -23
  36. package/dist/events/UnifiedSwapEventListener.js +132 -132
  37. package/dist/http/HttpUtils.d.ts +27 -27
  38. package/dist/http/HttpUtils.js +91 -91
  39. package/dist/http/paramcoders/IParamReader.d.ts +8 -8
  40. package/dist/http/paramcoders/IParamReader.js +2 -2
  41. package/dist/http/paramcoders/ParamDecoder.d.ts +44 -44
  42. package/dist/http/paramcoders/ParamDecoder.js +137 -137
  43. package/dist/http/paramcoders/ParamEncoder.d.ts +20 -20
  44. package/dist/http/paramcoders/ParamEncoder.js +36 -36
  45. package/dist/http/paramcoders/SchemaVerifier.d.ts +26 -26
  46. package/dist/http/paramcoders/SchemaVerifier.js +145 -145
  47. package/dist/http/paramcoders/client/ResponseParamDecoder.d.ts +11 -11
  48. package/dist/http/paramcoders/client/ResponseParamDecoder.js +57 -57
  49. package/dist/http/paramcoders/client/StreamParamEncoder.d.ts +13 -13
  50. package/dist/http/paramcoders/client/StreamParamEncoder.js +26 -26
  51. package/dist/http/paramcoders/client/StreamingFetchPromise.d.ts +16 -16
  52. package/dist/http/paramcoders/client/StreamingFetchPromise.js +174 -174
  53. package/dist/index.d.ts +85 -85
  54. package/dist/index.js +158 -158
  55. package/dist/intermediaries/Intermediary.d.ts +178 -178
  56. package/dist/intermediaries/Intermediary.js +166 -166
  57. package/dist/intermediaries/IntermediaryDiscovery.d.ts +211 -211
  58. package/dist/intermediaries/IntermediaryDiscovery.js +424 -424
  59. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +450 -450
  60. package/dist/intermediaries/apis/IntermediaryAPI.js +618 -618
  61. package/dist/intermediaries/apis/TrustedIntermediaryAPI.d.ts +155 -155
  62. package/dist/intermediaries/apis/TrustedIntermediaryAPI.js +137 -137
  63. package/dist/lnurl/LNURL.d.ts +102 -102
  64. package/dist/lnurl/LNURL.js +321 -321
  65. package/dist/prices/RedundantSwapPrice.d.ts +110 -110
  66. package/dist/prices/RedundantSwapPrice.js +222 -222
  67. package/dist/prices/SingleSwapPrice.d.ts +34 -34
  68. package/dist/prices/SingleSwapPrice.js +44 -44
  69. package/dist/prices/SwapPriceWithChain.d.ts +107 -107
  70. package/dist/prices/SwapPriceWithChain.js +128 -128
  71. package/dist/prices/abstract/ICachedSwapPrice.d.ts +28 -28
  72. package/dist/prices/abstract/ICachedSwapPrice.js +62 -62
  73. package/dist/prices/abstract/IPriceProvider.d.ts +81 -81
  74. package/dist/prices/abstract/IPriceProvider.js +74 -74
  75. package/dist/prices/abstract/ISwapPrice.d.ts +168 -168
  76. package/dist/prices/abstract/ISwapPrice.js +279 -279
  77. package/dist/prices/providers/BinancePriceProvider.d.ts +23 -23
  78. package/dist/prices/providers/BinancePriceProvider.js +30 -30
  79. package/dist/prices/providers/CoinGeckoPriceProvider.d.ts +23 -23
  80. package/dist/prices/providers/CoinGeckoPriceProvider.js +29 -29
  81. package/dist/prices/providers/CoinPaprikaPriceProvider.d.ts +25 -25
  82. package/dist/prices/providers/CoinPaprikaPriceProvider.js +29 -29
  83. package/dist/prices/providers/CustomPriceProvider.d.ts +24 -24
  84. package/dist/prices/providers/CustomPriceProvider.js +35 -35
  85. package/dist/prices/providers/KrakenPriceProvider.d.ts +38 -38
  86. package/dist/prices/providers/KrakenPriceProvider.js +45 -45
  87. package/dist/prices/providers/OKXPriceProvider.d.ts +34 -34
  88. package/dist/prices/providers/OKXPriceProvider.js +29 -29
  89. package/dist/prices/providers/abstract/ExchangePriceProvider.d.ts +17 -17
  90. package/dist/prices/providers/abstract/ExchangePriceProvider.js +21 -21
  91. package/dist/prices/providers/abstract/HttpPriceProvider.d.ts +7 -7
  92. package/dist/prices/providers/abstract/HttpPriceProvider.js +12 -12
  93. package/dist/storage/IUnifiedStorage.d.ts +85 -85
  94. package/dist/storage/IUnifiedStorage.js +2 -2
  95. package/dist/storage/UnifiedSwapStorage.d.ts +114 -114
  96. package/dist/storage/UnifiedSwapStorage.js +116 -116
  97. package/dist/storage-browser/IndexedDBUnifiedStorage.d.ts +63 -63
  98. package/dist/storage-browser/IndexedDBUnifiedStorage.js +298 -298
  99. package/dist/storage-browser/LocalStorageManager.d.ts +49 -49
  100. package/dist/storage-browser/LocalStorageManager.js +93 -93
  101. package/dist/swapper/Swapper.d.ts +732 -732
  102. package/dist/swapper/Swapper.js +1713 -1713
  103. package/dist/swapper/SwapperFactory.d.ts +135 -135
  104. package/dist/swapper/SwapperFactory.js +162 -162
  105. package/dist/swapper/SwapperUtils.d.ts +206 -206
  106. package/dist/swapper/SwapperUtils.js +481 -481
  107. package/dist/swapper/SwapperWithChain.d.ts +404 -404
  108. package/dist/swapper/SwapperWithChain.js +469 -469
  109. package/dist/swapper/SwapperWithSigner.d.ts +322 -322
  110. package/dist/swapper/SwapperWithSigner.js +318 -318
  111. package/dist/swaps/IAddressSwap.d.ts +22 -22
  112. package/dist/swaps/IAddressSwap.js +14 -14
  113. package/dist/swaps/IBTCWalletSwap.d.ts +73 -73
  114. package/dist/swaps/IBTCWalletSwap.js +18 -18
  115. package/dist/swaps/IClaimableSwap.d.ts +49 -49
  116. package/dist/swaps/IClaimableSwap.js +15 -15
  117. package/dist/swaps/IClaimableSwapWrapper.d.ts +15 -15
  118. package/dist/swaps/IClaimableSwapWrapper.js +2 -2
  119. package/dist/swaps/IRefundableSwap.d.ts +43 -43
  120. package/dist/swaps/IRefundableSwap.js +14 -14
  121. package/dist/swaps/ISwap.d.ts +392 -392
  122. package/dist/swaps/ISwap.js +349 -349
  123. package/dist/swaps/ISwapWithGasDrop.d.ts +21 -21
  124. package/dist/swaps/ISwapWithGasDrop.js +12 -12
  125. package/dist/swaps/ISwapWrapper.d.ts +285 -285
  126. package/dist/swaps/ISwapWrapper.js +353 -353
  127. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.d.ts +98 -98
  128. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.js +126 -126
  129. package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +139 -139
  130. package/dist/swaps/escrow_swaps/IEscrowSwap.js +170 -170
  131. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +128 -128
  132. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +167 -167
  133. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +105 -105
  134. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +129 -129
  135. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.d.ts +162 -162
  136. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +190 -190
  137. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.d.ts +64 -64
  138. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.js +82 -82
  139. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +531 -531
  140. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +1285 -1285
  141. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +190 -190
  142. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +432 -432
  143. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +583 -583
  144. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +1371 -1371
  145. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +235 -235
  146. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +525 -525
  147. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +458 -458
  148. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +1126 -1126
  149. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +202 -202
  150. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +406 -406
  151. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +403 -403
  152. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +924 -924
  153. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.d.ts +68 -68
  154. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +117 -117
  155. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.d.ts +127 -127
  156. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.js +256 -256
  157. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +251 -251
  158. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +536 -536
  159. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.d.ts +73 -73
  160. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.js +155 -155
  161. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +132 -132
  162. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +286 -286
  163. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +637 -637
  164. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +1448 -1448
  165. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +257 -257
  166. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +947 -947
  167. package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +261 -261
  168. package/dist/swaps/trusted/ln/LnForGasSwap.js +511 -511
  169. package/dist/swaps/trusted/ln/LnForGasWrapper.d.ts +40 -40
  170. package/dist/swaps/trusted/ln/LnForGasWrapper.js +83 -83
  171. package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +342 -342
  172. package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +715 -715
  173. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.d.ts +69 -69
  174. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +93 -93
  175. package/dist/types/AmountData.d.ts +10 -10
  176. package/dist/types/AmountData.js +2 -2
  177. package/dist/types/CustomPriceFunction.d.ts +11 -11
  178. package/dist/types/CustomPriceFunction.js +2 -2
  179. package/dist/types/PriceInfoType.d.ts +28 -28
  180. package/dist/types/PriceInfoType.js +57 -57
  181. package/dist/types/SwapExecutionAction.d.ts +88 -88
  182. package/dist/types/SwapExecutionAction.js +2 -2
  183. package/dist/types/SwapStateInfo.d.ts +5 -5
  184. package/dist/types/SwapStateInfo.js +2 -2
  185. package/dist/types/SwapWithSigner.d.ts +17 -17
  186. package/dist/types/SwapWithSigner.js +43 -43
  187. package/dist/types/Token.d.ts +99 -99
  188. package/dist/types/Token.js +76 -76
  189. package/dist/types/TokenAmount.d.ts +69 -69
  190. package/dist/types/TokenAmount.js +60 -60
  191. package/dist/types/fees/Fee.d.ts +50 -50
  192. package/dist/types/fees/Fee.js +2 -2
  193. package/dist/types/fees/FeeBreakdown.d.ts +11 -11
  194. package/dist/types/fees/FeeBreakdown.js +2 -2
  195. package/dist/types/fees/PercentagePPM.d.ts +17 -17
  196. package/dist/types/fees/PercentagePPM.js +18 -18
  197. package/dist/types/lnurl/LNURLPay.d.ts +61 -61
  198. package/dist/types/lnurl/LNURLPay.js +31 -31
  199. package/dist/types/lnurl/LNURLWithdraw.d.ts +48 -48
  200. package/dist/types/lnurl/LNURLWithdraw.js +27 -27
  201. package/dist/types/wallets/LightningInvoiceCreateService.d.ts +24 -24
  202. package/dist/types/wallets/LightningInvoiceCreateService.js +15 -15
  203. package/dist/types/wallets/MinimalBitcoinWalletInterface.d.ts +23 -23
  204. package/dist/types/wallets/MinimalBitcoinWalletInterface.js +2 -2
  205. package/dist/types/wallets/MinimalLightningNetworkWalletInterface.d.ts +9 -9
  206. package/dist/types/wallets/MinimalLightningNetworkWalletInterface.js +2 -2
  207. package/dist/utils/AutomaticClockDriftCorrection.d.ts +1 -1
  208. package/dist/utils/AutomaticClockDriftCorrection.js +70 -70
  209. package/dist/utils/BitcoinUtils.d.ts +16 -16
  210. package/dist/utils/BitcoinUtils.js +141 -141
  211. package/dist/utils/BitcoinWalletUtils.d.ts +7 -7
  212. package/dist/utils/BitcoinWalletUtils.js +14 -14
  213. package/dist/utils/Logger.d.ts +7 -7
  214. package/dist/utils/Logger.js +12 -12
  215. package/dist/utils/RetryUtils.d.ts +22 -22
  216. package/dist/utils/RetryUtils.js +67 -67
  217. package/dist/utils/SwapUtils.d.ts +88 -88
  218. package/dist/utils/SwapUtils.js +72 -72
  219. package/dist/utils/TimeoutUtils.d.ts +17 -17
  220. package/dist/utils/TimeoutUtils.js +55 -55
  221. package/dist/utils/TokenUtils.d.ts +19 -19
  222. package/dist/utils/TokenUtils.js +37 -37
  223. package/dist/utils/TypeUtils.d.ts +7 -7
  224. package/dist/utils/TypeUtils.js +2 -2
  225. package/dist/utils/Utils.d.ts +67 -67
  226. package/dist/utils/Utils.js +208 -208
  227. package/package.json +43 -43
  228. package/src/SmartChainAssets.ts +186 -186
  229. package/src/bitcoin/coinselect2/accumulative.ts +69 -69
  230. package/src/bitcoin/coinselect2/blackjack.ts +50 -50
  231. package/src/bitcoin/coinselect2/index.ts +93 -93
  232. package/src/bitcoin/coinselect2/utils.ts +236 -236
  233. package/src/bitcoin/wallet/BitcoinWallet.ts +439 -439
  234. package/src/bitcoin/wallet/IBitcoinWallet.ts +140 -140
  235. package/src/bitcoin/wallet/SingleAddressBitcoinWallet.ts +225 -225
  236. package/src/enums/FeeType.ts +15 -15
  237. package/src/enums/SwapAmountType.ts +16 -16
  238. package/src/enums/SwapDirection.ts +15 -15
  239. package/src/enums/SwapSide.ts +16 -16
  240. package/src/enums/SwapType.ts +75 -75
  241. package/src/errors/IntermediaryError.ts +28 -28
  242. package/src/errors/RequestError.ts +64 -64
  243. package/src/errors/UserError.ts +15 -15
  244. package/src/events/UnifiedSwapEventListener.ts +173 -173
  245. package/src/http/HttpUtils.ts +91 -91
  246. package/src/http/paramcoders/IParamReader.ts +9 -9
  247. package/src/http/paramcoders/ParamDecoder.ts +145 -145
  248. package/src/http/paramcoders/ParamEncoder.ts +40 -40
  249. package/src/http/paramcoders/SchemaVerifier.ts +153 -153
  250. package/src/http/paramcoders/client/ResponseParamDecoder.ts +57 -57
  251. package/src/http/paramcoders/client/StreamParamEncoder.ts +28 -28
  252. package/src/http/paramcoders/client/StreamingFetchPromise.ts +192 -192
  253. package/src/index.ts +140 -140
  254. package/src/intermediaries/Intermediary.ts +280 -280
  255. package/src/intermediaries/IntermediaryDiscovery.ts +541 -541
  256. package/src/intermediaries/apis/IntermediaryAPI.ts +963 -963
  257. package/src/intermediaries/apis/TrustedIntermediaryAPI.ts +257 -257
  258. package/src/lnurl/LNURL.ts +402 -402
  259. package/src/prices/RedundantSwapPrice.ts +264 -264
  260. package/src/prices/SingleSwapPrice.ts +50 -50
  261. package/src/prices/SwapPriceWithChain.ts +194 -194
  262. package/src/prices/abstract/ICachedSwapPrice.ts +85 -85
  263. package/src/prices/abstract/IPriceProvider.ts +127 -127
  264. package/src/prices/abstract/ISwapPrice.ts +390 -390
  265. package/src/prices/providers/BinancePriceProvider.ts +48 -48
  266. package/src/prices/providers/CoinGeckoPriceProvider.ts +46 -46
  267. package/src/prices/providers/CoinPaprikaPriceProvider.ts +49 -49
  268. package/src/prices/providers/CustomPriceProvider.ts +40 -40
  269. package/src/prices/providers/KrakenPriceProvider.ts +83 -83
  270. package/src/prices/providers/OKXPriceProvider.ts +59 -59
  271. package/src/prices/providers/abstract/ExchangePriceProvider.ts +31 -31
  272. package/src/prices/providers/abstract/HttpPriceProvider.ts +14 -14
  273. package/src/storage/IUnifiedStorage.ts +95 -95
  274. package/src/storage/UnifiedSwapStorage.ts +141 -141
  275. package/src/storage-browser/IndexedDBUnifiedStorage.ts +350 -350
  276. package/src/storage-browser/LocalStorageManager.ts +106 -106
  277. package/src/swapper/Swapper.ts +2488 -2488
  278. package/src/swapper/SwapperFactory.ts +307 -307
  279. package/src/swapper/SwapperUtils.ts +570 -570
  280. package/src/swapper/SwapperWithChain.ts +707 -707
  281. package/src/swapper/SwapperWithSigner.ts +511 -511
  282. package/src/swaps/IAddressSwap.ts +30 -30
  283. package/src/swaps/IBTCWalletSwap.ts +92 -92
  284. package/src/swaps/IClaimableSwap.ts +65 -65
  285. package/src/swaps/IClaimableSwapWrapper.ts +17 -17
  286. package/src/swaps/IRefundableSwap.ts +58 -58
  287. package/src/swaps/ISwap.ts +703 -703
  288. package/src/swaps/ISwapWithGasDrop.ts +25 -25
  289. package/src/swaps/ISwapWrapper.ts +539 -539
  290. package/src/swaps/escrow_swaps/IEscrowSelfInitSwap.ts +217 -217
  291. package/src/swaps/escrow_swaps/IEscrowSwap.ts +269 -269
  292. package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +282 -282
  293. package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +169 -169
  294. package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +300 -300
  295. package/src/swaps/escrow_swaps/frombtc/IFromBTCWrapper.ts +107 -107
  296. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +1473 -1474
  297. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +601 -601
  298. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +1582 -1582
  299. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +750 -750
  300. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +1299 -1299
  301. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +610 -610
  302. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +1096 -1096
  303. package/src/swaps/escrow_swaps/tobtc/IToBTCWrapper.ts +138 -138
  304. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.ts +304 -304
  305. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +786 -786
  306. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.ts +206 -206
  307. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +401 -401
  308. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +1812 -1812
  309. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +1236 -1236
  310. package/src/swaps/trusted/ln/LnForGasSwap.ts +589 -589
  311. package/src/swaps/trusted/ln/LnForGasWrapper.ts +91 -91
  312. package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +862 -862
  313. package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +131 -131
  314. package/src/types/AmountData.ts +9 -9
  315. package/src/types/CustomPriceFunction.ts +11 -11
  316. package/src/types/PriceInfoType.ts +66 -66
  317. package/src/types/SwapExecutionAction.ts +99 -99
  318. package/src/types/SwapStateInfo.ts +6 -6
  319. package/src/types/SwapWithSigner.ts +61 -61
  320. package/src/types/Token.ts +163 -163
  321. package/src/types/TokenAmount.ts +132 -132
  322. package/src/types/fees/Fee.ts +56 -56
  323. package/src/types/fees/FeeBreakdown.ts +11 -11
  324. package/src/types/fees/PercentagePPM.ts +26 -26
  325. package/src/types/lnurl/LNURLPay.ts +79 -79
  326. package/src/types/lnurl/LNURLWithdraw.ts +61 -61
  327. package/src/types/wallets/LightningInvoiceCreateService.ts +30 -30
  328. package/src/types/wallets/MinimalBitcoinWalletInterface.ts +21 -21
  329. package/src/types/wallets/MinimalLightningNetworkWalletInterface.ts +9 -9
  330. package/src/utils/AutomaticClockDriftCorrection.ts +71 -71
  331. package/src/utils/BitcoinUtils.ts +132 -132
  332. package/src/utils/BitcoinWalletUtils.ts +15 -15
  333. package/src/utils/Logger.ts +14 -14
  334. package/src/utils/RetryUtils.ts +78 -78
  335. package/src/utils/SwapUtils.ts +99 -99
  336. package/src/utils/TimeoutUtils.ts +49 -49
  337. package/src/utils/TokenUtils.ts +33 -33
  338. package/src/utils/TypeUtils.ts +8 -8
  339. package/src/utils/Utils.ts +212 -212
@@ -1,1713 +1,1713 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Swapper = void 0;
4
- const base_1 = require("@atomiqlabs/base");
5
- const ToBTCLNWrapper_1 = require("../swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper");
6
- const ToBTCWrapper_1 = require("../swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper");
7
- const FromBTCLNWrapper_1 = require("../swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper");
8
- const FromBTCWrapper_1 = require("../swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper");
9
- const IntermediaryDiscovery_1 = require("../intermediaries/IntermediaryDiscovery");
10
- const bolt11_1 = require("@atomiqlabs/bolt11");
11
- const IntermediaryError_1 = require("../errors/IntermediaryError");
12
- const SwapType_1 = require("../enums/SwapType");
13
- const LnForGasWrapper_1 = require("../swaps/trusted/ln/LnForGasWrapper");
14
- const events_1 = require("events");
15
- const Utils_1 = require("../utils/Utils");
16
- const RequestError_1 = require("../errors/RequestError");
17
- const SwapperWithChain_1 = require("./SwapperWithChain");
18
- const OnchainForGasWrapper_1 = require("../swaps/trusted/onchain/OnchainForGasWrapper");
19
- const utils_1 = require("@scure/btc-signer/utils");
20
- const UnifiedSwapStorage_1 = require("../storage/UnifiedSwapStorage");
21
- const UnifiedSwapEventListener_1 = require("../events/UnifiedSwapEventListener");
22
- const SpvFromBTCWrapper_1 = require("../swaps/spv_swaps/SpvFromBTCWrapper");
23
- const SpvFromBTCSwap_1 = require("../swaps/spv_swaps/SpvFromBTCSwap");
24
- const SwapperUtils_1 = require("./SwapperUtils");
25
- const FromBTCLNAutoWrapper_1 = require("../swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper");
26
- const UserError_1 = require("../errors/UserError");
27
- const AutomaticClockDriftCorrection_1 = require("../utils/AutomaticClockDriftCorrection");
28
- const SwapUtils_1 = require("../utils/SwapUtils");
29
- const IndexedDBUnifiedStorage_1 = require("../storage-browser/IndexedDBUnifiedStorage");
30
- const TokenAmount_1 = require("../types/TokenAmount");
31
- const Token_1 = require("../types/Token");
32
- const Logger_1 = require("../utils/Logger");
33
- const LNURLWithdraw_1 = require("../types/lnurl/LNURLWithdraw");
34
- const LNURLPay_1 = require("../types/lnurl/LNURLPay");
35
- const RetryUtils_1 = require("../utils/RetryUtils");
36
- const IEscrowSwap_1 = require("../swaps/escrow_swaps/IEscrowSwap");
37
- const LightningInvoiceCreateService_1 = require("../types/wallets/LightningInvoiceCreateService");
38
- const BitcoinWalletUtils_1 = require("../utils/BitcoinWalletUtils");
39
- /**
40
- * Core orchestrator for all atomiq swap operations
41
- *
42
- * @category Core
43
- */
44
- class Swapper extends events_1.EventEmitter {
45
- /**
46
- * @internal
47
- */
48
- constructor(bitcoinRpc, lightningApi, bitcoinSynchronizer, chainsData, pricing, tokens, messenger, options) {
49
- super();
50
- this.logger = (0, Logger_1.getLogger)(this.constructor.name + ": ");
51
- this.initialized = false;
52
- /**
53
- * Helper information about various swap protocol and their features:
54
- * - `requiresInputWallet`: Whether a swap requires a connected wallet on the input chain able to sign
55
- * arbitrary transaction
56
- * - `requiresOutputWallet`: Whether a swap requires a connected wallet on the output chain able to sign
57
- * arbitrary transactions
58
- * - `supportsGasDrop`: Whether a swap supports the "gas drop" feature, allowing to user to receive a small
59
- * amount of native token as part of the swap when swapping to smart chains
60
- *
61
- * Uses a `Record` type here, use the {@link SwapProtocolInfo} import for a literal readonly type, with
62
- * pre-filled exact values in the type.
63
- */
64
- this.SwapTypeInfo = SwapUtils_1.SwapProtocolInfo;
65
- const storagePrefix = options?.storagePrefix ?? "atomiq-";
66
- options ??= {};
67
- options.saveUninitializedSwaps ??= true;
68
- options.bitcoinNetwork = options.bitcoinNetwork == null ? base_1.BitcoinNetwork.TESTNET : options.bitcoinNetwork;
69
- const swapStorage = options.swapStorage ??= (name) => new IndexedDBUnifiedStorage_1.IndexedDBUnifiedStorage(name);
70
- this.options = options;
71
- this.bitcoinNetwork = options.bitcoinNetwork;
72
- this._btcNetwork = options.bitcoinNetwork === base_1.BitcoinNetwork.MAINNET ? utils_1.NETWORK :
73
- (options.bitcoinNetwork === base_1.BitcoinNetwork.TESTNET || options.bitcoinNetwork === base_1.BitcoinNetwork.TESTNET4) ? utils_1.TEST_NETWORK : {
74
- bech32: 'bcrt',
75
- pubKeyHash: 111,
76
- scriptHash: 196,
77
- wif: 239
78
- };
79
- this.Utils = new SwapperUtils_1.SwapperUtils(this);
80
- this.prices = pricing;
81
- this._bitcoinRpc = bitcoinRpc;
82
- this.messenger = messenger;
83
- this._tokens = {};
84
- this._tokensByTicker = {};
85
- for (let tokenData of tokens) {
86
- const chainId = tokenData.chainId;
87
- this._tokens[chainId] ??= {};
88
- this._tokensByTicker[chainId] ??= {};
89
- this._tokens[chainId][tokenData.address] = this._tokensByTicker[chainId][tokenData.ticker] = tokenData;
90
- }
91
- this.swapStateListener = (swap) => {
92
- this.emit("swapState", swap);
93
- };
94
- this._chains = (0, Utils_1.objectMap)(chainsData, (chainData, key) => {
95
- let { chainInterface, chainEvents, chainId, btcRelay, swapContract, swapDataConstructor, spvVaultContract, spvVaultWithdrawalDataConstructor, spvVaultDataConstructor, defaultVersion, versions } = chainData;
96
- defaultVersion ??= "v1";
97
- if (versions == null) {
98
- versions = {
99
- [defaultVersion]: {
100
- btcRelay,
101
- swapContract,
102
- swapDataConstructor,
103
- spvVaultContract,
104
- spvVaultDataConstructor,
105
- spvVaultWithdrawalDataConstructor
106
- }
107
- };
108
- }
109
- const versionedContracts = (0, Utils_1.objectMap)(versions, (value, key) => {
110
- return {
111
- swapContract: value.swapContract,
112
- spvVaultContract: value.spvVaultContract,
113
- btcRelay: value.btcRelay,
114
- synchronizer: bitcoinSynchronizer(value.btcRelay)
115
- };
116
- });
117
- const storageHandler = swapStorage(storagePrefix + chainId);
118
- const unifiedSwapStorage = new UnifiedSwapStorage_1.UnifiedSwapStorage(storageHandler, this.options.noSwapCache);
119
- const unifiedChainEvents = new UnifiedSwapEventListener_1.UnifiedSwapEventListener(unifiedSwapStorage, chainEvents);
120
- const wrappers = {};
121
- wrappers[SwapType_1.SwapType.TO_BTCLN] = new ToBTCLNWrapper_1.ToBTCLNWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, {
122
- getRequestTimeout: this.options.getRequestTimeout,
123
- postRequestTimeout: this.options.postRequestTimeout,
124
- saveUninitializedSwaps: this.options.saveUninitializedSwaps,
125
- });
126
- wrappers[SwapType_1.SwapType.TO_BTC] = new ToBTCWrapper_1.ToBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, this._bitcoinRpc, {
127
- getRequestTimeout: this.options.getRequestTimeout,
128
- postRequestTimeout: this.options.postRequestTimeout,
129
- saveUninitializedSwaps: this.options.saveUninitializedSwaps,
130
- bitcoinNetwork: this._btcNetwork
131
- });
132
- wrappers[SwapType_1.SwapType.FROM_BTCLN] = new FromBTCLNWrapper_1.FromBTCLNWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, lightningApi, {
133
- getRequestTimeout: this.options.getRequestTimeout,
134
- postRequestTimeout: this.options.postRequestTimeout,
135
- saveUninitializedSwaps: this.options.saveUninitializedSwaps,
136
- unsafeSkipLnNodeCheck: this.bitcoinNetwork === base_1.BitcoinNetwork.TESTNET4 || this.bitcoinNetwork === base_1.BitcoinNetwork.REGTEST
137
- });
138
- wrappers[SwapType_1.SwapType.FROM_BTC] = new FromBTCWrapper_1.FromBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, versionedContracts, this._bitcoinRpc, {
139
- getRequestTimeout: this.options.getRequestTimeout,
140
- postRequestTimeout: this.options.postRequestTimeout,
141
- saveUninitializedSwaps: this.options.saveUninitializedSwaps,
142
- bitcoinNetwork: this._btcNetwork
143
- });
144
- wrappers[SwapType_1.SwapType.TRUSTED_FROM_BTCLN] = new LnForGasWrapper_1.LnForGasWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], {
145
- getRequestTimeout: this.options.getRequestTimeout,
146
- postRequestTimeout: this.options.postRequestTimeout,
147
- saveUninitializedSwaps: this.options.saveUninitializedSwaps,
148
- });
149
- wrappers[SwapType_1.SwapType.TRUSTED_FROM_BTC] = new OnchainForGasWrapper_1.OnchainForGasWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], bitcoinRpc, {
150
- getRequestTimeout: this.options.getRequestTimeout,
151
- postRequestTimeout: this.options.postRequestTimeout,
152
- saveUninitializedSwaps: this.options.saveUninitializedSwaps,
153
- bitcoinNetwork: this._btcNetwork
154
- });
155
- // This is gated on the default version of the contracts
156
- if (spvVaultContract != null) {
157
- wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC] = new SpvFromBTCWrapper_1.SpvFromBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, versionedContracts, bitcoinRpc, {
158
- getRequestTimeout: this.options.getRequestTimeout,
159
- postRequestTimeout: this.options.postRequestTimeout,
160
- saveUninitializedSwaps: this.options.saveUninitializedSwaps,
161
- bitcoinNetwork: this._btcNetwork
162
- });
163
- }
164
- // This is gated on the default version of the contracts
165
- if (swapContract.supportsInitWithoutClaimer) {
166
- wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] = new FromBTCLNAutoWrapper_1.FromBTCLNAutoWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, lightningApi, this.messenger, {
167
- getRequestTimeout: this.options.getRequestTimeout,
168
- postRequestTimeout: this.options.postRequestTimeout,
169
- saveUninitializedSwaps: this.options.saveUninitializedSwaps,
170
- unsafeSkipLnNodeCheck: this.bitcoinNetwork === base_1.BitcoinNetwork.TESTNET4 || this.bitcoinNetwork === base_1.BitcoinNetwork.REGTEST
171
- });
172
- }
173
- Object.keys(wrappers).forEach(key => wrappers[key].events.on("swapState", this.swapStateListener));
174
- const reviver = (val) => {
175
- const wrapper = wrappers[val.type];
176
- if (wrapper == null)
177
- return null;
178
- return new wrapper._swapDeserializer(wrapper, val);
179
- };
180
- return {
181
- chainEvents,
182
- chainInterface,
183
- wrappers,
184
- unifiedChainEvents,
185
- unifiedSwapStorage,
186
- defaultVersion,
187
- reviver,
188
- versionedContracts
189
- };
190
- });
191
- const contracts = (0, Utils_1.objectMap)(chainsData, (data) => data.versions ?? { [data.defaultVersion ?? "v1"]: { swapContract: data.swapContract, spvVaultContract: data.spvVaultContract } });
192
- if (options.intermediaryUrl != null) {
193
- this.intermediaryDiscovery = new IntermediaryDiscovery_1.IntermediaryDiscovery(contracts, options.registryUrl, Array.isArray(options.intermediaryUrl) ? options.intermediaryUrl : [options.intermediaryUrl], options.getRequestTimeout);
194
- }
195
- else {
196
- this.intermediaryDiscovery = new IntermediaryDiscovery_1.IntermediaryDiscovery(contracts, options.registryUrl, undefined, options.getRequestTimeout);
197
- }
198
- this.intermediaryDiscovery.on("removed", (intermediaries) => {
199
- this.emit("lpsRemoved", intermediaries);
200
- });
201
- this.intermediaryDiscovery.on("added", (intermediaries) => {
202
- this.emit("lpsAdded", intermediaries);
203
- });
204
- }
205
- async _init() {
206
- this.logger.debug("init(): Initializing swapper...");
207
- const abortController = new AbortController();
208
- const promises = [];
209
- let automaticClockDriftCorrectionPromise = undefined;
210
- if (this.options.automaticClockDriftCorrection) {
211
- promises.push(automaticClockDriftCorrectionPromise = (0, RetryUtils_1.tryWithRetries)(AutomaticClockDriftCorrection_1.correctClock, undefined, undefined, abortController.signal).catch((err) => {
212
- abortController.abort(err);
213
- }));
214
- }
215
- this.logger.debug("init(): Initializing intermediary discovery");
216
- if (!this.options.dontFetchLPs)
217
- promises.push(this.intermediaryDiscovery.init(abortController.signal).catch(err => {
218
- if (abortController.signal.aborted)
219
- return;
220
- this.logger.error("init(): Failed to fetch intermediaries/LPs: ", err);
221
- }));
222
- if (this.options.defaultTrustedIntermediaryUrl != null) {
223
- promises.push(this.intermediaryDiscovery.getIntermediary(this.options.defaultTrustedIntermediaryUrl, abortController.signal)
224
- .then(val => {
225
- if (val == null)
226
- throw new Error("Cannot get trusted LP");
227
- this.defaultTrustedIntermediary = val;
228
- })
229
- .catch(err => {
230
- if (abortController.signal.aborted)
231
- return;
232
- this.logger.error("init(): Failed to contact trusted LP url: ", err);
233
- }));
234
- }
235
- if (automaticClockDriftCorrectionPromise != null) {
236
- //We should await the promises here before checking the swaps
237
- await automaticClockDriftCorrectionPromise;
238
- }
239
- const chainPromises = [];
240
- for (let chainIdentifier in this._chains) {
241
- chainPromises.push((async () => {
242
- const { chainInterface, versionedContracts, unifiedChainEvents, unifiedSwapStorage, wrappers, reviver } = this._chains[chainIdentifier];
243
- const _chainInterface = chainInterface;
244
- if (_chainInterface.verifyNetwork != null) {
245
- await _chainInterface.verifyNetwork(this.bitcoinNetwork);
246
- }
247
- for (let contractVersion in versionedContracts) {
248
- await versionedContracts[contractVersion].swapContract.start();
249
- this.logger.debug("init(): Intialized swap contract: " + chainIdentifier + ` version: ${contractVersion}`);
250
- }
251
- await unifiedSwapStorage.init();
252
- if (unifiedSwapStorage.storage instanceof IndexedDBUnifiedStorage_1.IndexedDBUnifiedStorage) {
253
- //Try to migrate the data here
254
- const storagePrefix = chainIdentifier === "SOLANA" ?
255
- "SOLv4-" + this.bitcoinNetwork + "-Swaps-" :
256
- "atomiqsdk-" + this.bitcoinNetwork + chainIdentifier + "-Swaps-";
257
- await unifiedSwapStorage.storage.tryMigrate([
258
- [storagePrefix + "FromBTC", SwapType_1.SwapType.FROM_BTC],
259
- [storagePrefix + "FromBTCLN", SwapType_1.SwapType.FROM_BTCLN],
260
- [storagePrefix + "ToBTC", SwapType_1.SwapType.TO_BTC],
261
- [storagePrefix + "ToBTCLN", SwapType_1.SwapType.TO_BTCLN]
262
- ], (obj) => {
263
- const swap = reviver(obj);
264
- if (swap._randomNonce == null) {
265
- const oldIdentifierHash = swap.getId();
266
- swap._randomNonce = (0, Utils_1.randomBytes)(16).toString("hex");
267
- const newIdentifierHash = swap.getId();
268
- this.logger.info("init(): Found older swap version without randomNonce, replacing, old hash: " + oldIdentifierHash +
269
- " new hash: " + newIdentifierHash);
270
- }
271
- return swap;
272
- });
273
- }
274
- if (!this.options.noEvents)
275
- await unifiedChainEvents.start();
276
- this.logger.debug("init(): Intialized events: " + chainIdentifier);
277
- for (let key in wrappers) {
278
- // this.logger.debug("init(): Initializing "+SwapType[key]+": "+chainIdentifier);
279
- await wrappers[key].init(this.options.noTimers, this.options.dontCheckPastSwaps);
280
- }
281
- })());
282
- }
283
- await Promise.all(chainPromises);
284
- await Promise.all(promises);
285
- this.logger.debug("init(): Initializing messenger");
286
- await this.messenger.init();
287
- }
288
- /**
289
- * Initializes the swap storage and loads existing swaps, needs to be called before any other action
290
- */
291
- async init() {
292
- if (this.initialized)
293
- return;
294
- if (this.initPromise != null) {
295
- await this.initPromise;
296
- return;
297
- }
298
- try {
299
- const promise = this._init();
300
- this.initPromise = promise;
301
- await promise;
302
- delete this.initPromise;
303
- this.initialized = true;
304
- }
305
- catch (e) {
306
- delete this.initPromise;
307
- throw e;
308
- }
309
- }
310
- /**
311
- * Stops listening for onchain events and closes this Swapper instance
312
- */
313
- async stop() {
314
- if (this.initPromise)
315
- await this.initPromise;
316
- for (let chainIdentifier in this._chains) {
317
- const { wrappers, unifiedChainEvents } = this._chains[chainIdentifier];
318
- for (let key in wrappers) {
319
- const wrapper = wrappers[key];
320
- wrapper.events.removeListener("swapState", this.swapStateListener);
321
- await wrapper.stop();
322
- }
323
- await unifiedChainEvents.stop();
324
- await this.messenger.stop();
325
- }
326
- this.initialized = false;
327
- }
328
- /**
329
- * Creates swap & handles intermediary, quote selection
330
- *
331
- * @param chainIdentifier
332
- * @param create Callback to create the
333
- * @param amountData Amount data as passed to the function
334
- * @param swapType Swap type of the execution
335
- * @param maxWaitTimeMS Maximum waiting time after the first intermediary returns the quote
336
- * @private
337
- * @throws {Error} when no intermediary was found
338
- * @throws {Error} if the chain with the provided identifier cannot be found
339
- */
340
- async createSwap(chainIdentifier, create, amountData, swapType, maxWaitTimeMS = 2000) {
341
- if (!this.initialized)
342
- throw new Error("Swapper not initialized, init first with swapper.init()!");
343
- if (this._chains[chainIdentifier] == null)
344
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
345
- let candidates;
346
- const inBtc = swapType === SwapType_1.SwapType.TO_BTCLN || swapType === SwapType_1.SwapType.TO_BTC ? !amountData.exactIn : amountData.exactIn;
347
- if (!inBtc || amountData.amount == null) {
348
- //Get candidates not based on the amount
349
- candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token);
350
- }
351
- else {
352
- candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token, amountData.amount);
353
- }
354
- let swapLimitsChanged = false;
355
- if (candidates.length === 0) {
356
- this.logger.warn("createSwap(): No valid intermediary found to execute the swap with, reloading intermediary database...");
357
- await this.intermediaryDiscovery.reloadIntermediaries();
358
- swapLimitsChanged = true;
359
- if (!inBtc || amountData.amount == null) {
360
- //Get candidates not based on the amount
361
- candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token);
362
- }
363
- else {
364
- candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token, amountData.amount);
365
- if (candidates.length === 0) {
366
- const min = this.intermediaryDiscovery.getSwapMinimum(chainIdentifier, swapType, amountData.token);
367
- const max = this.intermediaryDiscovery.getSwapMaximum(chainIdentifier, swapType, amountData.token);
368
- if (min != null && max != null) {
369
- if (amountData.amount < BigInt(min))
370
- throw new RequestError_1.OutOfBoundsError("Swap amount too low! Try swapping a higher amount.", 200, BigInt(min), BigInt(max));
371
- if (amountData.amount > BigInt(max))
372
- throw new RequestError_1.OutOfBoundsError("Swap amount too high! Try swapping a lower amount.", 200, BigInt(min), BigInt(max));
373
- }
374
- }
375
- }
376
- if (candidates.length === 0)
377
- throw new Error("No intermediary found for the requested pair and amount! You can try swapping different pair or higher/lower amount.");
378
- }
379
- const abortController = new AbortController();
380
- this.logger.debug("createSwap() Swap candidates: ", candidates.map(lp => lp.url).join());
381
- const quotePromises = await create(candidates, abortController.signal, this._chains[chainIdentifier]);
382
- const promiseAll = new Promise((resolve, reject) => {
383
- let min;
384
- let max;
385
- let error;
386
- let numResolved = 0;
387
- let quotes = [];
388
- let timeout;
389
- quotePromises.forEach(data => {
390
- data.quote.then(quote => {
391
- if (numResolved === 0) {
392
- timeout = setTimeout(() => {
393
- abortController.abort(new Error("Timed out waiting for quote!"));
394
- resolve(quotes);
395
- }, maxWaitTimeMS);
396
- }
397
- numResolved++;
398
- quotes.push({
399
- quote,
400
- intermediary: data.intermediary
401
- });
402
- if (numResolved === quotePromises.length) {
403
- clearTimeout(timeout);
404
- resolve(quotes);
405
- return;
406
- }
407
- }).catch(e => {
408
- numResolved++;
409
- if (e instanceof IntermediaryError_1.IntermediaryError) {
410
- //Blacklist that node
411
- this.intermediaryDiscovery.removeIntermediary(data.intermediary);
412
- swapLimitsChanged = true;
413
- }
414
- else if (e instanceof RequestError_1.OutOfBoundsError) {
415
- if (min == null || max == null) {
416
- min = e.min;
417
- max = e.max;
418
- }
419
- else {
420
- min = (0, Utils_1.bigIntMin)(min, e.min);
421
- max = (0, Utils_1.bigIntMax)(max, e.max);
422
- }
423
- data.intermediary.swapBounds[swapType] ??= {};
424
- data.intermediary.swapBounds[swapType][chainIdentifier] ??= {};
425
- const tokenBoundsData = (data.intermediary.swapBounds[swapType][chainIdentifier][amountData.token] ??= { input: {}, output: {} });
426
- if (amountData.exactIn) {
427
- tokenBoundsData.input = { min: e.min, max: e.max };
428
- }
429
- else {
430
- tokenBoundsData.output = { min: e.min, max: e.max };
431
- }
432
- swapLimitsChanged = true;
433
- }
434
- this.logger.warn("createSwap(): Intermediary " + data.intermediary.url + " error: ", e);
435
- error = e;
436
- if (numResolved === quotePromises.length) {
437
- if (timeout != null)
438
- clearTimeout(timeout);
439
- if (quotes.length > 0) {
440
- resolve(quotes);
441
- return;
442
- }
443
- if (min != null && max != null) {
444
- let msg = "Swap amount too high or too low! Try swapping a different amount.";
445
- if (amountData.amount != null) {
446
- if (min > amountData.amount)
447
- msg = "Swap amount too low! Try swapping a higher amount.";
448
- if (max < amountData.amount)
449
- msg = "Swap amount too high! Try swapping a lower amount.";
450
- }
451
- reject(new RequestError_1.OutOfBoundsError(msg, 400, min, max));
452
- return;
453
- }
454
- reject(error);
455
- }
456
- });
457
- });
458
- });
459
- try {
460
- const quotes = await promiseAll;
461
- //TODO: Intermediary's reputation is not taken into account!
462
- quotes.sort((a, b) => {
463
- if (amountData.exactIn) {
464
- //Compare outputs
465
- return (0, Utils_1.bigIntCompare)(b.quote.getOutput().rawAmount, a.quote.getOutput().rawAmount);
466
- }
467
- else {
468
- //Compare inputs
469
- return (0, Utils_1.bigIntCompare)(a.quote.getInput().rawAmount, b.quote.getInput().rawAmount);
470
- }
471
- });
472
- this.logger.debug("createSwap(): Sorted quotes, best price to worst: ", quotes);
473
- if (swapLimitsChanged)
474
- this.emit("swapLimitsChanged");
475
- const quote = quotes[0].quote;
476
- await quote._save();
477
- return quote;
478
- }
479
- catch (e) {
480
- if (swapLimitsChanged)
481
- this.emit("swapLimitsChanged");
482
- throw e;
483
- }
484
- }
485
- /**
486
- * Creates Smart chain -> Bitcoin ({@link SwapType.TO_BTC}) swap
487
- *
488
- * @param chainIdentifier Chain identifier string of the source smart chain
489
- * @param signer Signer's address on the source chain
490
- * @param tokenAddress Token address to pay with
491
- * @param address Recipient's bitcoin address
492
- * @param amount Amount to send in token based units (if `exactIn=true`) or receive in satoshis (if `exactIn=false`)
493
- * @param exactIn Whether to use exact in instead of exact out
494
- * @param additionalParams Additional parameters sent to the LP when creating the swap
495
- * @param options Additional options for the swap
496
- */
497
- createToBTCSwap(chainIdentifier, signer, tokenAddress, address, amount, exactIn = false, additionalParams = this.options.defaultAdditionalParameters, options) {
498
- if (this._chains[chainIdentifier] == null)
499
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
500
- if (address.startsWith("bitcoin:")) {
501
- address = address.substring(8).split("?")[0];
502
- }
503
- if (!this.Utils.isValidBitcoinAddress(address))
504
- throw new Error("Invalid bitcoin address");
505
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(signer, true))
506
- throw new Error("Invalid " + chainIdentifier + " address");
507
- signer = this._chains[chainIdentifier].chainInterface.normalizeAddress(signer);
508
- const amountData = {
509
- amount,
510
- token: tokenAddress,
511
- exactIn
512
- };
513
- return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType_1.SwapType.TO_BTC].create(signer, address, amountData, candidates, options, additionalParams, abortSignal)), amountData, SwapType_1.SwapType.TO_BTC);
514
- }
515
- /**
516
- * Creates Smart chain -> Bitcoin Lightning ({@link SwapType.TO_BTCLN}) swap
517
- *
518
- * @param chainIdentifier Chain identifier string of the source smart chain
519
- * @param signer Signer's address on the source chain
520
- * @param tokenAddress Token address to pay with
521
- * @param paymentRequest BOLT11 lightning network invoice to be paid (needs to have a fixed amount), and the swap
522
- * amount is taken from this fixed amount, hence only exact output swaps are supported
523
- * @param additionalParams Additional parameters sent to the LP when creating the swap
524
- * @param options Additional options for the swap
525
- */
526
- async createToBTCLNSwap(chainIdentifier, signer, tokenAddress, paymentRequest, additionalParams = this.options.defaultAdditionalParameters, options) {
527
- if (this._chains[chainIdentifier] == null)
528
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
529
- if (paymentRequest.startsWith("lightning:"))
530
- paymentRequest = paymentRequest.substring(10);
531
- if (!this.Utils.isValidLightningInvoice(paymentRequest))
532
- throw new Error("Invalid lightning network invoice");
533
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(signer, true))
534
- throw new Error("Invalid " + chainIdentifier + " address");
535
- signer = this._chains[chainIdentifier].chainInterface.normalizeAddress(signer);
536
- const parsedPR = (0, bolt11_1.decode)(paymentRequest);
537
- if (parsedPR.millisatoshis == null)
538
- throw new Error("Invalid lightning network invoice, no msat value field!");
539
- const amountData = {
540
- amount: (BigInt(parsedPR.millisatoshis) + 999n) / 1000n,
541
- token: tokenAddress,
542
- exactIn: false
543
- };
544
- return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => chain.wrappers[SwapType_1.SwapType.TO_BTCLN].create(signer, paymentRequest, amountData, candidates, options, additionalParams, abortSignal), amountData, SwapType_1.SwapType.TO_BTCLN);
545
- }
546
- /**
547
- * Creates Smart chain -> Bitcoin Lightning ({@link SwapType.TO_BTCLN}) swap via LNURL-pay link
548
- *
549
- * @param chainIdentifier Chain identifier string of the source smart chain
550
- * @param signer Signer's address on the source chain
551
- * @param tokenAddress Token address to pay with
552
- * @param lnurlPay LNURL-pay link to use for the payment
553
- * @param amount Amount to send in token based units (if `exactIn=true`) or receive in satoshis (if `exactIn=false`)
554
- * @param exactIn Whether to do an exact in swap instead of exact out
555
- * @param additionalParams Additional parameters sent to the LP when creating the swap
556
- * @param options Additional options for the swap
557
- */
558
- async createToBTCLNSwapViaLNURL(chainIdentifier, signer, tokenAddress, lnurlPay, amount, exactIn = false, additionalParams = this.options.defaultAdditionalParameters, options) {
559
- if (this._chains[chainIdentifier] == null)
560
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
561
- if (typeof (lnurlPay) === "string" && !this.Utils.isValidLNURL(lnurlPay))
562
- throw new Error("Invalid LNURL-pay link");
563
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(signer, true))
564
- throw new Error("Invalid " + chainIdentifier + " address");
565
- signer = this._chains[chainIdentifier].chainInterface.normalizeAddress(signer);
566
- const amountData = {
567
- amount,
568
- token: tokenAddress,
569
- exactIn
570
- };
571
- return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => chain.wrappers[SwapType_1.SwapType.TO_BTCLN].createViaLNURL(signer, typeof (lnurlPay) === "string" ? (lnurlPay.startsWith("lightning:") ? lnurlPay.substring(10) : lnurlPay) : lnurlPay.params, amountData, candidates, options, additionalParams, abortSignal), amountData, SwapType_1.SwapType.TO_BTCLN);
572
- }
573
- /**
574
- * Creates Smart chain -> Bitcoin Lightning ({@link SwapType.TO_BTCLN}) swap via {@link LightningInvoiceCreateService}
575
- *
576
- * @param chainIdentifier Chain identifier string of the source smart chain
577
- * @param signer Signer's address on the source chain
578
- * @param tokenAddress Token address to pay with
579
- * @param service Invoice create service object which facilitates the creation of fixed amount LN invoices
580
- * @param amount Amount to send in token based units (if `exactIn=true`) or receive in satoshis (if `exactIn=false`)
581
- * @param exactIn Whether to do an exact in swap instead of exact out
582
- * @param additionalParams Additional parameters sent to the LP when creating the swap
583
- * @param options Additional options for the swap
584
- */
585
- async createToBTCLNSwapViaInvoiceCreateService(chainIdentifier, signer, tokenAddress, service, amount, exactIn = false, additionalParams = this.options.defaultAdditionalParameters, options) {
586
- if (this._chains[chainIdentifier] == null)
587
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
588
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(signer, true))
589
- throw new Error("Invalid " + chainIdentifier + " address");
590
- signer = this._chains[chainIdentifier].chainInterface.normalizeAddress(signer);
591
- const amountData = {
592
- amount,
593
- token: tokenAddress,
594
- exactIn
595
- };
596
- return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => chain.wrappers[SwapType_1.SwapType.TO_BTCLN].createViaInvoiceCreateService(signer, Promise.resolve(service), amountData, candidates, options, additionalParams, abortSignal), amountData, SwapType_1.SwapType.TO_BTCLN);
597
- }
598
- /**
599
- * Creates Bitcoin -> Smart chain ({@link SwapType.SPV_VAULT_FROM_BTC}) swap
600
- *
601
- * @param chainIdentifier Chain identifier string of the destination smart chain
602
- * @param recipient Recipient address on the destination chain
603
- * @param tokenAddress Token address to receive
604
- * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
605
- * @param exactOut Whether to use a exact out instead of exact in
606
- * @param additionalParams Additional parameters sent to the LP when creating the swap
607
- * @param options Additional options for the swap
608
- */
609
- async createFromBTCSwapNew(chainIdentifier, recipient, tokenAddress, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
610
- if (this._chains[chainIdentifier] == null)
611
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
612
- if (this._chains[chainIdentifier].wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC] == null)
613
- throw new Error("Chain " + chainIdentifier + " doesn't support new BTC swap protocol (spv vault swaps)!");
614
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
615
- throw new Error("Invalid " + chainIdentifier + " address");
616
- recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
617
- const amountData = {
618
- amount: amount ?? undefined,
619
- token: tokenAddress,
620
- exactIn: !exactOut
621
- };
622
- return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC].create(recipient, amountData, candidates, options, additionalParams, abortSignal)), amountData, SwapType_1.SwapType.SPV_VAULT_FROM_BTC);
623
- }
624
- /**
625
- * Creates LEGACY Bitcoin -> Smart chain ({@link SwapType.FROM_BTC}) swap
626
- *
627
- * @param chainIdentifier Chain identifier string of the destination smart chain
628
- * @param recipient Recipient address on the destination chain
629
- * @param tokenAddress Token address to receive
630
- * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
631
- * @param exactOut Whether to use a exact out instead of exact in
632
- * @param additionalParams Additional parameters sent to the LP when creating the swap
633
- * @param options Additional options for the swap
634
- */
635
- async createFromBTCSwap(chainIdentifier, recipient, tokenAddress, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
636
- if (this._chains[chainIdentifier] == null)
637
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
638
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
639
- throw new Error("Invalid " + chainIdentifier + " address");
640
- recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
641
- const amountData = {
642
- amount,
643
- token: tokenAddress,
644
- exactIn: !exactOut
645
- };
646
- return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType_1.SwapType.FROM_BTC].create(recipient, amountData, candidates, options, additionalParams, abortSignal)), amountData, SwapType_1.SwapType.FROM_BTC);
647
- }
648
- /**
649
- * Creates LEGACY Bitcoin Lightning -> Smart chain ({@link SwapType.FROM_BTCLN}) swap
650
- *
651
- * @param chainIdentifier Chain identifier string of the destination smart chain
652
- * @param recipient Recipient address on the destination chain
653
- * @param tokenAddress Token address to receive
654
- * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
655
- * @param exactOut Whether to use a exact out instead of exact in
656
- * @param additionalParams Additional parameters sent to the LP when creating the swap
657
- * @param options Additional options for the swap
658
- */
659
- async createFromBTCLNSwap(chainIdentifier, recipient, tokenAddress, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
660
- if (this._chains[chainIdentifier] == null)
661
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
662
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
663
- throw new Error("Invalid " + chainIdentifier + " address");
664
- recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
665
- const amountData = {
666
- amount,
667
- token: tokenAddress,
668
- exactIn: !exactOut
669
- };
670
- return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType_1.SwapType.FROM_BTCLN].create(recipient, amountData, candidates, options, additionalParams, abortSignal)), amountData, SwapType_1.SwapType.FROM_BTCLN);
671
- }
672
- /**
673
- * Creates LEGACY Bitcoin Lightning -> Smart chain ({@link SwapType.FROM_BTCLN}) swap, withdrawing from
674
- * an LNURL-withdraw link
675
- *
676
- * @param chainIdentifier Chain identifier string of the destination smart chain
677
- * @param recipient Recipient address on the destination chain
678
- * @param tokenAddress Token address to receive
679
- * @param lnurl LNURL-withdraw link to pull the funds from
680
- * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
681
- * @param exactOut Whether to use a exact out instead of exact in
682
- * @param additionalParams Additional parameters sent to the LP when creating the swap
683
- * @param options Additional options for the swap
684
- */
685
- async createFromBTCLNSwapViaLNURL(chainIdentifier, recipient, tokenAddress, lnurl, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
686
- if (this._chains[chainIdentifier] == null)
687
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
688
- if (typeof (lnurl) === "string" && !this.Utils.isValidLNURL(lnurl))
689
- throw new Error("Invalid LNURL-withdraw link");
690
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
691
- throw new Error("Invalid " + chainIdentifier + " address");
692
- recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
693
- const amountData = {
694
- amount,
695
- token: tokenAddress,
696
- exactIn: !exactOut
697
- };
698
- return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => chain.wrappers[SwapType_1.SwapType.FROM_BTCLN].createViaLNURL(recipient, typeof (lnurl) === "string" ? (lnurl.startsWith("lightning:") ? lnurl.substring(10) : lnurl) : lnurl.params, amountData, candidates, options, additionalParams, abortSignal), amountData, SwapType_1.SwapType.FROM_BTCLN);
699
- }
700
- /**
701
- * Creates Bitcoin Lightning -> Smart chain ({@link SwapType.FROM_BTCLN_AUTO}) swap
702
- *
703
- * @param chainIdentifier Chain identifier string of the destination smart chain
704
- * @param recipient Recipient address on the destination chain
705
- * @param tokenAddress Token address to receive
706
- * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
707
- * @param exactOut Whether to use a exact out instead of exact in
708
- * @param additionalParams Additional parameters sent to the LP when creating the swap
709
- * @param options Additional options for the swap
710
- */
711
- async createFromBTCLNSwapNew(chainIdentifier, recipient, tokenAddress, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
712
- if (this._chains[chainIdentifier] == null)
713
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
714
- if (this._chains[chainIdentifier].wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] == null)
715
- throw new Error("Chain " + chainIdentifier + " doesn't support new lightning swap protocol (from btcln auto)!");
716
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
717
- throw new Error("Invalid " + chainIdentifier + " address");
718
- recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
719
- const amountData = {
720
- amount,
721
- token: tokenAddress,
722
- exactIn: !exactOut
723
- };
724
- return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO].create(recipient, amountData, candidates, options, additionalParams, abortSignal)), amountData, SwapType_1.SwapType.FROM_BTCLN_AUTO);
725
- }
726
- /**
727
- * Creates Bitcoin Lightning -> Smart chain ({@link SwapType.FROM_BTCLN_AUTO}) swap, withdrawing from
728
- * an LNURL-withdraw link
729
- *
730
- * @param chainIdentifier Chain identifier string of the destination smart chain
731
- * @param recipient Recipient address on the destination chain
732
- * @param tokenAddress Token address to receive
733
- * @param lnurl LNURL-withdraw link to pull the funds from
734
- * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
735
- * @param exactOut Whether to use a exact out instead of exact in
736
- * @param additionalParams Additional parameters sent to the LP when creating the swap
737
- * @param options Additional options for the swap
738
- */
739
- async createFromBTCLNSwapNewViaLNURL(chainIdentifier, recipient, tokenAddress, lnurl, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
740
- if (this._chains[chainIdentifier] == null)
741
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
742
- if (this._chains[chainIdentifier].wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] == null)
743
- throw new Error("Chain " + chainIdentifier + " doesn't support new lightning swap protocol (from btcln auto)!");
744
- if (typeof (lnurl) === "string" && !this.Utils.isValidLNURL(lnurl))
745
- throw new Error("Invalid LNURL-withdraw link");
746
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
747
- throw new Error("Invalid " + chainIdentifier + " address");
748
- recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
749
- const amountData = {
750
- amount,
751
- token: tokenAddress,
752
- exactIn: !exactOut
753
- };
754
- return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => chain.wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO].createViaLNURL(recipient, typeof (lnurl) === "string" ? (lnurl.startsWith("lightning:") ? lnurl.substring(10) : lnurl) : lnurl.params, amountData, candidates, options, additionalParams, abortSignal), amountData, SwapType_1.SwapType.FROM_BTCLN_AUTO);
755
- }
756
- /**
757
- * Creates a trusted Bitcoin Lightning -> Smart chain ({@link SwapType.TRUSTED_FROM_BTCLN}) gas swap
758
- *
759
- * @param chainIdentifier Chain identifier string of the destination smart chain
760
- * @param recipient Recipient address on the destination chain
761
- * @param amount Amount of native token to receive, in base units
762
- * @param trustedIntermediaryOrUrl URL or Intermediary object of the trusted intermediary to use, otherwise uses default
763
- * @throws {Error} If no trusted intermediary specified
764
- */
765
- async createTrustedLNForGasSwap(chainIdentifier, recipient, amount, trustedIntermediaryOrUrl) {
766
- if (this._chains[chainIdentifier] == null)
767
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
768
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
769
- throw new Error("Invalid " + chainIdentifier + " address");
770
- recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
771
- const useUrl = trustedIntermediaryOrUrl ?? this.defaultTrustedIntermediary ?? this.options.defaultTrustedIntermediaryUrl;
772
- if (useUrl == null)
773
- throw new Error("No trusted intermediary specified!");
774
- const swap = await this._chains[chainIdentifier].wrappers[SwapType_1.SwapType.TRUSTED_FROM_BTCLN].create(recipient, amount, useUrl);
775
- await swap._save();
776
- return swap;
777
- }
778
- /**
779
- * Creates a trusted Bitcoin -> Smart chain ({@link SwapType.TRUSTED_FROM_BTC}) gas swap
780
- *
781
- * @param chainIdentifier Chain identifier string of the destination smart chain
782
- * @param recipient Recipient address on the destination chain
783
- * @param amount Amount of native token to receive, in base units
784
- * @param refundAddress Bitcoin refund address, in case the swap fails the funds are refunded here
785
- * @param trustedIntermediaryOrUrl URL or Intermediary object of the trusted intermediary to use, otherwise uses default
786
- * @throws {Error} If no trusted intermediary specified
787
- */
788
- async createTrustedOnchainForGasSwap(chainIdentifier, recipient, amount, refundAddress, trustedIntermediaryOrUrl) {
789
- if (this._chains[chainIdentifier] == null)
790
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
791
- if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
792
- throw new Error("Invalid " + chainIdentifier + " address");
793
- recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
794
- const useUrl = trustedIntermediaryOrUrl ?? this.defaultTrustedIntermediary ?? this.options.defaultTrustedIntermediaryUrl;
795
- if (useUrl == null)
796
- throw new Error("No trusted intermediary specified!");
797
- const swap = await this._chains[chainIdentifier].wrappers[SwapType_1.SwapType.TRUSTED_FROM_BTC].create(recipient, amount, useUrl, refundAddress);
798
- await swap._save();
799
- return swap;
800
- }
801
- /**
802
- * Creates a swap from srcToken to dstToken, of a specific token amount, either specifying input amount (exactIn=true)
803
- * or output amount (exactIn=false), NOTE: For regular -> BTC-LN (lightning) swaps the passed amount is ignored and
804
- * invoice's pre-set amount is used instead.
805
- * @deprecated Use {@link swap} instead
806
- *
807
- * @param signer Smartchain (Solana, Starknet, etc.) address of the user
808
- * @param srcToken Source token of the swap, user pays this token
809
- * @param dstToken Destination token of the swap, user receives this token
810
- * @param amount Amount of the swap
811
- * @param exactIn Whether the amount specified is an input amount (exactIn=true) or an output amount (exactIn=false)
812
- * @param addressLnurlLightningInvoice Bitcoin on-chain address, lightning invoice, LNURL-pay to pay or
813
- * LNURL-withdrawal to withdraw money from
814
- */
815
- create(signer, srcToken, dstToken, amount, exactIn, addressLnurlLightningInvoice) {
816
- if (srcToken.chain === "BTC") {
817
- return this.swap(srcToken, dstToken, amount, exactIn, addressLnurlLightningInvoice, signer);
818
- }
819
- else {
820
- return this.swap(srcToken, dstToken, amount, exactIn, signer, addressLnurlLightningInvoice);
821
- }
822
- }
823
- /**
824
- * Creates a swap from srcToken to dstToken, of a specific token amount, either specifying input amount (if `exactIn=true`)
825
- * or output amount (if `exactIn=false`), NOTE: For regular Smart chain -> BTC-LN (lightning) swaps the passed amount is ignored and
826
- * invoice's pre-set amount is used instead, use LNURL-pay links for dynamic amounts
827
- *
828
- * @param _srcToken Source token of the swap, user pays this token
829
- * @param _dstToken Destination token of the swap, user receives this token
830
- * @param _amount Amount of the swap either in base units as {bigint} or in human readable format (with decimals) as {string}
831
- * @param exactIn Whether the amount specified is an input amount (exactIn=true) or an output amount (exactIn=false)
832
- * @param src Source wallet/lnurl-withdraw of the swap
833
- * @param dst Destination smart chain address, bitcoin on-chain address, lightning invoice, LNURL-pay
834
- * @param options Options for the swap
835
- */
836
- swap(_srcToken, _dstToken, _amount, exactIn, src, dst, options) {
837
- const srcToken = typeof (_srcToken) === "string" ? this.getToken(_srcToken) : _srcToken;
838
- const dstToken = typeof (_dstToken) === "string" ? this.getToken(_dstToken) : _dstToken;
839
- const amount = _amount == null ? null : (typeof (_amount) === "bigint" ? _amount : (0, Utils_1.fromDecimal)(_amount, exactIn ? srcToken.decimals : dstToken.decimals));
840
- if ((0, Token_1.isBtcToken)(srcToken)) {
841
- if ((0, Token_1.isSCToken)(dstToken)) {
842
- if (typeof (dst) !== "string")
843
- throw new Error("Destination for BTC/BTC-LN -> smart chain swaps must be a smart chain address!");
844
- if (amount == null)
845
- throw new Error("Amount cannot be null for from btc swaps!");
846
- if (srcToken.lightning) {
847
- //FROM_BTCLN
848
- if (src != null) {
849
- if (typeof (src) !== "string" && !(0, LNURLWithdraw_1.isLNURLWithdraw)(src))
850
- throw new Error("LNURL must be a string or LNURLWithdraw object!");
851
- return this.supportsSwapType(dstToken.chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO) ?
852
- this.createFromBTCLNSwapNewViaLNURL(dstToken.chainId, dst, dstToken.address, src, amount, !exactIn, undefined, options) :
853
- this.createFromBTCLNSwapViaLNURL(dstToken.chainId, dst, dstToken.address, src, amount, !exactIn, undefined, options);
854
- }
855
- else {
856
- return this.supportsSwapType(dstToken.chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO) ?
857
- this.createFromBTCLNSwapNew(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options) :
858
- this.createFromBTCLNSwap(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options);
859
- }
860
- }
861
- else {
862
- //FROM_BTC
863
- if (this.supportsSwapType(dstToken.chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC)) {
864
- return this.createFromBTCSwapNew(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options);
865
- }
866
- else {
867
- return this.createFromBTCSwap(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options);
868
- }
869
- }
870
- }
871
- }
872
- else if ((0, Token_1.isSCToken)(srcToken)) {
873
- if ((0, Token_1.isBtcToken)(dstToken)) {
874
- if (typeof (src) !== "string")
875
- throw new Error("Source address for BTC/BTC-LN -> smart chain swaps must be a smart chain address!");
876
- if (dstToken.lightning) {
877
- //TO_BTCLN
878
- if (typeof (dst) !== "string" && !(0, LNURLPay_1.isLNURLPay)(dst))
879
- throw new Error("Destination LNURL link/lightning invoice must be a string or LNURLPay object!");
880
- if ((0, LNURLPay_1.isLNURLPay)(dst) || this.Utils.isValidLNURL(dst)) {
881
- if (amount == null)
882
- throw new Error("Amount cannot be null for to btcln swaps via LNURL-pay!");
883
- return this.createToBTCLNSwapViaLNURL(srcToken.chainId, src, srcToken.address, dst, amount, !!exactIn, undefined, options);
884
- }
885
- else if ((0, LightningInvoiceCreateService_1.isLightningInvoiceCreateService)(dst)) {
886
- if (amount == null)
887
- throw new Error("Amount cannot be null for to btcln swaps via InvoiceCreateService!");
888
- return this.createToBTCLNSwapViaInvoiceCreateService(srcToken.chainId, src, srcToken.address, dst, amount, !!exactIn, undefined, options);
889
- }
890
- else if (this.Utils.isLightningInvoice(dst)) {
891
- if (!this.Utils.isValidLightningInvoice(dst))
892
- throw new Error("Invalid lightning invoice specified, lightning invoice MUST contain pre-set amount!");
893
- if (exactIn)
894
- throw new Error("Only exact out swaps are possible with lightning invoices, use LNURL links for exact in lightning swaps!");
895
- return this.createToBTCLNSwap(srcToken.chainId, src, srcToken.address, dst, undefined, options);
896
- }
897
- else {
898
- throw new Error("Supplied parameter is not LNURL link nor lightning invoice (bolt11)!");
899
- }
900
- }
901
- else {
902
- //TO_BTC
903
- if (typeof (dst) !== "string")
904
- throw new Error("Destination bitcoin address must be a string!");
905
- if (amount == null)
906
- throw new Error("Amount cannot be null for to btc swaps!");
907
- return this.createToBTCSwap(srcToken.chainId, src, srcToken.address, dst, amount, !!exactIn, undefined, options);
908
- }
909
- }
910
- }
911
- throw new Error("Unsupported swap type");
912
- }
913
- /**
914
- * A helper function to sweep all the funds from a given wallet in a single swap, after getting the quote you can
915
- * execute the swap by passing the returned `feeRate` and `utxos` to the {@link SpvFromBTCSwap.execute},
916
- * {@link SpvFromBTCSwap.getFundedPsbt} or {@link SpvFromBTCSwap.sendBitcoinTransaction} functions along
917
- * with `spendFully=true`.
918
- *
919
- * @example
920
- * Create the swap first using this function
921
- * ```ts
922
- * const {swap, utxos, btcFeeRate} = await swapper.sweepBitcoinWallet(wallet, Tokens.CITREA.CBTC, dstAddress);
923
- * ```
924
- * Then execute it using one of these execution paths - ensure that you supply the returned `utxos`, `btcFeeRate`
925
- * params and also set `spendFully` to `true`!
926
- *
927
- * a) Execute and pass the returned utxos and btcFeeRate:
928
- * ```ts
929
- * await swap.execute(wallet, undefined, {feeRate: btcFeeRate, utxos: utxos, spendFully: true});
930
- * ```
931
- *
932
- * b) Get funded PSBT to sign externally:
933
- * ```ts
934
- * const {psbt, psbtHex, psbtBase64, signInputs} = await swap.getFundedPsbt(wallet, btcFeeRate, undefined, utxos, true);
935
- * // Sign the psbt at the specified signInputs indices
936
- * const signedPsbt = ...;
937
- * // Then submit back to the SDK
938
- * await swap.submitPsbt(signedPsbt);
939
- * ```
940
- *
941
- * c) Only sign and send the signed PSBT with the provided wallet:
942
- * ```ts
943
- * await swap.sendBitcoinTransaction(wallet, btcFeeRate, utxos, true);
944
- * ```
945
- */
946
- async sweepBitcoinWallet(srcWallet, _dstToken, dstAddress, options) {
947
- const dstToken = typeof (_dstToken) === "string" ? this.getToken(_dstToken) : _dstToken;
948
- if (!(0, Token_1.isSCToken)(dstToken))
949
- throw new Error("Destination token must be a smart chain token!");
950
- const wallet = (0, BitcoinWalletUtils_1.toBitcoinWallet)(srcWallet, this._bitcoinRpc, this.bitcoinNetwork);
951
- if (wallet.getUtxoPool == null)
952
- throw new Error("Wallet needs to support the `getUtxoPool()` function!");
953
- const walletUtxosPromise = wallet.getUtxoPool();
954
- const bitcoinFeeRatePromise = options?.bitcoinFeeRate ?? wallet.getFeeRate();
955
- const swap = await this.createFromBTCSwapNew(dstToken.chainId, dstAddress, dstToken.address, null, false, undefined, {
956
- ...options,
957
- sourceWalletUtxos: walletUtxosPromise,
958
- bitcoinFeeRate: bitcoinFeeRatePromise
959
- });
960
- return {
961
- swap,
962
- utxos: await walletUtxosPromise,
963
- btcFeeRate: Math.max(swap.minimumBtcFeeRate, await bitcoinFeeRatePromise)
964
- };
965
- }
966
- async getAllSwaps(chainId, signer) {
967
- const queryParams = [];
968
- if (signer != null)
969
- queryParams.push({ key: "initiator", value: signer });
970
- if (chainId == null) {
971
- const res = await Promise.all(Object.keys(this._chains).map((chainId) => {
972
- const { unifiedSwapStorage, reviver } = this._chains[chainId];
973
- return unifiedSwapStorage.query([queryParams], reviver);
974
- }));
975
- return res.flat();
976
- }
977
- else {
978
- const { unifiedSwapStorage, reviver } = this._chains[chainId];
979
- return await unifiedSwapStorage.query([queryParams], reviver);
980
- }
981
- }
982
- async getActionableSwaps(chainId, signer) {
983
- if (chainId == null) {
984
- const res = await Promise.all(Object.keys(this._chains).map((chainId) => {
985
- const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
986
- const queryParams = [];
987
- for (let key in wrappers) {
988
- const wrapper = wrappers[key];
989
- const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
990
- if (signer != null)
991
- swapTypeQueryParams.push({ key: "initiator", value: signer });
992
- swapTypeQueryParams.push({ key: "state", value: wrapper._pendingSwapStates });
993
- queryParams.push(swapTypeQueryParams);
994
- }
995
- return unifiedSwapStorage.query(queryParams, reviver);
996
- }));
997
- return res.flat().filter(swap => swap.requiresAction());
998
- }
999
- else {
1000
- const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1001
- const queryParams = [];
1002
- for (let key in wrappers) {
1003
- const wrapper = wrappers[key];
1004
- const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1005
- if (signer != null)
1006
- swapTypeQueryParams.push({ key: "initiator", value: signer });
1007
- swapTypeQueryParams.push({ key: "state", value: wrapper._pendingSwapStates });
1008
- queryParams.push(swapTypeQueryParams);
1009
- }
1010
- return (await unifiedSwapStorage.query(queryParams, reviver)).filter(swap => swap.requiresAction());
1011
- }
1012
- }
1013
- async getRefundableSwaps(chainId, signer) {
1014
- if (chainId == null) {
1015
- const res = await Promise.all(Object.keys(this._chains).map((chainId) => {
1016
- const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1017
- const queryParams = [];
1018
- for (let wrapper of [wrappers[SwapType_1.SwapType.TO_BTCLN], wrappers[SwapType_1.SwapType.TO_BTC]]) {
1019
- const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1020
- if (signer != null)
1021
- swapTypeQueryParams.push({ key: "initiator", value: signer });
1022
- swapTypeQueryParams.push({ key: "state", value: wrapper._refundableSwapStates });
1023
- queryParams.push(swapTypeQueryParams);
1024
- }
1025
- return unifiedSwapStorage.query(queryParams, reviver);
1026
- }));
1027
- return res.flat().filter(swap => swap.isRefundable());
1028
- }
1029
- else {
1030
- const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1031
- const queryParams = [];
1032
- for (let wrapper of [wrappers[SwapType_1.SwapType.TO_BTCLN], wrappers[SwapType_1.SwapType.TO_BTC]]) {
1033
- const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1034
- if (signer != null)
1035
- swapTypeQueryParams.push({ key: "initiator", value: signer });
1036
- swapTypeQueryParams.push({ key: "state", value: wrapper._refundableSwapStates });
1037
- queryParams.push(swapTypeQueryParams);
1038
- }
1039
- const result = await unifiedSwapStorage.query(queryParams, reviver);
1040
- return result.filter(swap => swap.isRefundable());
1041
- }
1042
- }
1043
- async getClaimableSwaps(chainId, signer) {
1044
- if (chainId == null) {
1045
- const res = await Promise.all(Object.keys(this._chains).map((chainId) => {
1046
- const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1047
- const queryParams = [];
1048
- for (let wrapper of [wrappers[SwapType_1.SwapType.FROM_BTC], wrappers[SwapType_1.SwapType.FROM_BTCLN], wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC], wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO]]) {
1049
- if (wrapper == null)
1050
- continue;
1051
- const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1052
- if (signer != null)
1053
- swapTypeQueryParams.push({ key: "initiator", value: signer });
1054
- swapTypeQueryParams.push({ key: "state", value: wrapper._claimableSwapStates });
1055
- queryParams.push(swapTypeQueryParams);
1056
- }
1057
- return unifiedSwapStorage.query(queryParams, reviver);
1058
- }));
1059
- return res.flat().filter(swap => swap.isClaimable());
1060
- }
1061
- else {
1062
- const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1063
- const queryParams = [];
1064
- for (let wrapper of [wrappers[SwapType_1.SwapType.FROM_BTC], wrappers[SwapType_1.SwapType.FROM_BTCLN], wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC], wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO]]) {
1065
- if (wrapper == null)
1066
- continue;
1067
- const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1068
- if (signer != null)
1069
- swapTypeQueryParams.push({ key: "initiator", value: signer });
1070
- swapTypeQueryParams.push({ key: "state", value: wrapper._claimableSwapStates });
1071
- queryParams.push(swapTypeQueryParams);
1072
- }
1073
- const result = await unifiedSwapStorage.query(queryParams, reviver);
1074
- return result.filter(swap => swap.isClaimable());
1075
- }
1076
- }
1077
- async getSwapById(id, chainId, signer) {
1078
- //Check in pending swaps first
1079
- if (chainId != null) {
1080
- for (let key in this._chains[chainId].wrappers) {
1081
- const wrapper = this._chains[chainId].wrappers[key];
1082
- const result = wrapper._getPendingSwap(id);
1083
- if (result != null) {
1084
- if (signer != null) {
1085
- if (result._getInitiator() === signer)
1086
- return result;
1087
- }
1088
- else {
1089
- return result;
1090
- }
1091
- }
1092
- }
1093
- }
1094
- else {
1095
- for (let chainId in this._chains) {
1096
- for (let key in this._chains[chainId].wrappers) {
1097
- const wrapper = this._chains[chainId].wrappers[key];
1098
- const result = wrapper._getPendingSwap(id);
1099
- if (result != null) {
1100
- if (signer != null) {
1101
- if (result._getInitiator() === signer)
1102
- return result;
1103
- }
1104
- else {
1105
- return result;
1106
- }
1107
- }
1108
- }
1109
- }
1110
- }
1111
- const queryParams = [];
1112
- if (signer != null)
1113
- queryParams.push({ key: "initiator", value: signer });
1114
- queryParams.push({ key: "id", value: id });
1115
- if (chainId == null) {
1116
- const res = await Promise.all(Object.keys(this._chains).map((chainId) => {
1117
- const { unifiedSwapStorage, reviver } = this._chains[chainId];
1118
- return unifiedSwapStorage.query([queryParams], reviver);
1119
- }));
1120
- return res.flat()[0];
1121
- }
1122
- else {
1123
- const { unifiedSwapStorage, reviver } = this._chains[chainId];
1124
- return (await unifiedSwapStorage.query([queryParams], reviver))[0];
1125
- }
1126
- }
1127
- /**
1128
- * Returns the swap with a proper return type, or `undefined` if not found or has wrong type
1129
- *
1130
- * @param id An ID of the swap ({@link ISwap.getId})
1131
- * @param chainId Chain identifier of the smart chain where the swap was initiated
1132
- * @param swapType Type of the swap
1133
- * @param signer An optional required smart chain signer address to fetch the swap for
1134
- */
1135
- async getTypedSwapById(id, chainId, swapType, signer) {
1136
- let _swapType = swapType;
1137
- if (swapType === SwapType_1.SwapType.FROM_BTC && this.supportsSwapType(chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC))
1138
- _swapType = SwapType_1.SwapType.SPV_VAULT_FROM_BTC;
1139
- if (swapType === SwapType_1.SwapType.FROM_BTCLN && this.supportsSwapType(chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO))
1140
- _swapType = SwapType_1.SwapType.FROM_BTCLN_AUTO;
1141
- const wrapper = this._chains[chainId].wrappers[_swapType];
1142
- if (wrapper == null)
1143
- return;
1144
- const result = wrapper._getPendingSwap(id);
1145
- if (result != null) {
1146
- if (signer != null) {
1147
- if (result._getInitiator() === signer)
1148
- return result;
1149
- }
1150
- else {
1151
- return result;
1152
- }
1153
- }
1154
- const queryParams = [];
1155
- if (signer != null)
1156
- queryParams.push({ key: "initiator", value: signer });
1157
- queryParams.push({ key: "id", value: id });
1158
- const { unifiedSwapStorage, reviver } = this._chains[chainId];
1159
- const swap = (await unifiedSwapStorage.query([queryParams], reviver))[0];
1160
- if ((0, SwapUtils_1.isSwapType)(swap, swapType))
1161
- return swap;
1162
- }
1163
- async syncSwapsForChain(chainId, signer) {
1164
- const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1165
- const queryParams = [];
1166
- for (let key in wrappers) {
1167
- const wrapper = wrappers[key];
1168
- const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1169
- if (signer != null)
1170
- swapTypeQueryParams.push({ key: "initiator", value: signer });
1171
- swapTypeQueryParams.push({ key: "state", value: wrapper._pendingSwapStates });
1172
- queryParams.push(swapTypeQueryParams);
1173
- }
1174
- this.logger.debug("_syncSwaps(): Querying swaps swaps for chain " + chainId + "!");
1175
- const swaps = await unifiedSwapStorage.query(queryParams, reviver);
1176
- this.logger.debug("_syncSwaps(): Syncing " + swaps.length + " swaps!");
1177
- const changedSwaps = [];
1178
- const removeSwaps = [];
1179
- const assortedSwaps = {};
1180
- swaps.forEach(swap => {
1181
- (assortedSwaps[swap.getType()] ??= []).push(swap);
1182
- });
1183
- for (let key in assortedSwaps) {
1184
- const swapType = key;
1185
- const wrapperSwaps = assortedSwaps[swapType];
1186
- const wrapper = wrappers[swapType];
1187
- const result = await wrapper.checkPastSwaps(wrapperSwaps, true);
1188
- changedSwaps.push(...result.changedSwaps);
1189
- removeSwaps.push(...result.removeSwaps);
1190
- }
1191
- this.logger.debug("_syncSwaps(): Done syncing " + swaps.length + " swaps, saving " + changedSwaps.length + " changed swaps, removing " + removeSwaps.length + " swaps!");
1192
- await unifiedSwapStorage.saveAll(changedSwaps);
1193
- await unifiedSwapStorage.removeAll(removeSwaps);
1194
- changedSwaps.forEach(swap => swap._emitEvent());
1195
- removeSwaps.forEach(swap => swap._emitEvent());
1196
- }
1197
- /**
1198
- * Deletes the swaps from the persistent storage backend. Note that some data (like lightning network
1199
- * amounts and bolt11 invoices) are purely off-chain and can never be recovered later just from
1200
- * on-chain data!
1201
- *
1202
- * @param chainId Optional, to only delete swaps for this smart chain
1203
- * @param signer Optional, to only delete swaps for this smart chain signer (`chainId` param must be
1204
- * set to delete only signer's swaps)
1205
- */
1206
- async wipeStorage(chainId, signer) {
1207
- if (chainId == null) {
1208
- const swaps = await this.getAllSwaps();
1209
- const chainSwaps = {};
1210
- swaps.forEach(swap => (chainSwaps[swap.chainIdentifier] ??= []).push(swap));
1211
- for (let chainId in chainSwaps) {
1212
- const currentChainSwaps = chainSwaps[chainId];
1213
- if (this._chains[chainId] == null) {
1214
- this.logger.warn(`wipeStorage(): Attempted to remove ${currentChainSwaps.length} swaps on ${chainId}, but smart chain not known!`);
1215
- continue;
1216
- }
1217
- await this._chains[chainId].unifiedSwapStorage.removeAll(currentChainSwaps);
1218
- this.logger.debug(`wipeStorage(): Successfully removed ${currentChainSwaps.length} swaps on ${chainId}!`);
1219
- }
1220
- }
1221
- else {
1222
- if (this._chains[chainId] == null)
1223
- throw new Error(`wipeStorage(): Smart chain with identifier ${chainId} not found!`);
1224
- const swaps = await this.getAllSwaps(chainId, signer);
1225
- await this._chains[chainId].unifiedSwapStorage.removeAll(swaps);
1226
- this.logger.debug(`wipeStorage(): Successfully removed ${swaps.length} swaps on ${chainId}!`);
1227
- }
1228
- }
1229
- /**
1230
- * Synchronizes swaps from on-chain, this is ran automatically when SDK is initialized, hence
1231
- * should only be ran manually when `dontCheckPastSwaps=true` is passed in the swapper options,
1232
- * also deletes expired quotes
1233
- *
1234
- * @param chainId Optional chain identifier to only run swap sync for a single smart chain
1235
- * @param signer Optional signer to only run swap sync for swaps initiated by this signer
1236
- */
1237
- async _syncSwaps(chainId, signer) {
1238
- if (chainId == null) {
1239
- await Promise.all(Object.keys(this._chains).map((chainId) => {
1240
- return this.syncSwapsForChain(chainId, signer);
1241
- }));
1242
- }
1243
- else {
1244
- await this.syncSwapsForChain(chainId, signer);
1245
- }
1246
- }
1247
- /**
1248
- * Recovers swaps from on-chain historical data.
1249
- *
1250
- * Please note that the recovered swaps might not be complete (i.e. missing amounts or addresses), as some
1251
- * of the swap data is purely off-chain and can never be recovered purely from on-chain data. This
1252
- * functions tries to recover as much swap data as possible.
1253
- *
1254
- * @param chainId Smart chain identifier string to recover the swaps from
1255
- * @param signer Signer address to recover the swaps for
1256
- * @param startBlockheight Optional starting blockheight for swap data recovery, will only check swaps
1257
- * initiated after this blockheight
1258
- */
1259
- async recoverSwaps(chainId, signer, startBlockheight) {
1260
- //TODO: Recover swaps from all the known contract versions
1261
- const { versionedContracts, unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1262
- const recoveredSwaps = [];
1263
- let someVersionSupportsRecovery = false;
1264
- const recoveredEscrowStates = {};
1265
- const recoveredSpvStates = {};
1266
- for (let contractVersion in versionedContracts) {
1267
- const { swapContract, spvVaultContract } = versionedContracts[contractVersion];
1268
- if (swapContract.getHistoricalSwaps == null ||
1269
- (spvVaultContract != null && spvVaultContract.getHistoricalWithdrawalStates == null)) {
1270
- this.logger.warn(`recoverSwaps(): Swap data recovery not supported on ${chainId}, with contract version ${contractVersion}`);
1271
- continue;
1272
- }
1273
- someVersionSupportsRecovery = true;
1274
- const { swaps } = await swapContract.getHistoricalSwaps(signer, startBlockheight);
1275
- const spvVaultData = wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC] == null
1276
- ? undefined
1277
- : await spvVaultContract?.getHistoricalWithdrawalStates(signer, startBlockheight);
1278
- for (let key in swaps)
1279
- recoveredEscrowStates[key] = { ...swaps[key], contractVersion };
1280
- if (spvVaultData != null)
1281
- for (let key in spvVaultData.withdrawals)
1282
- (recoveredSpvStates[contractVersion] ??= {})[key] = spvVaultData.withdrawals[key];
1283
- }
1284
- if (!someVersionSupportsRecovery)
1285
- throw new Error(`Historical swap recovery is not supported for ${chainId}`);
1286
- const escrowHashes = Object.keys(recoveredEscrowStates);
1287
- for (let contractVersion in recoveredSpvStates)
1288
- Object.keys(recoveredSpvStates[contractVersion]).forEach(btcTxId => escrowHashes.push(btcTxId));
1289
- this.logger.debug(`recoverSwaps(): Loaded on-chain data for ${escrowHashes.length} swaps`);
1290
- this.logger.debug(`recoverSwaps(): Fetching if swap escrowHashes are known: ${escrowHashes.join(", ")}`);
1291
- const knownSwapsArray = await unifiedSwapStorage.query([[{ key: "escrowHash", value: escrowHashes }]], reviver);
1292
- const knownSwaps = {};
1293
- knownSwapsArray.forEach(val => {
1294
- const escrowHash = val._getEscrowHash();
1295
- if (escrowHash != null)
1296
- knownSwaps[escrowHash] = val;
1297
- });
1298
- this.logger.debug(`recoverSwaps(): Fetched known swaps escrowHashes: ${Object.keys(knownSwaps).join(", ")}`);
1299
- for (let escrowHash in recoveredEscrowStates) {
1300
- const { init, state, contractVersion } = recoveredEscrowStates[escrowHash];
1301
- const knownSwap = knownSwaps[escrowHash];
1302
- const { swapContract } = versionedContracts[contractVersion];
1303
- if (knownSwap == null) {
1304
- if (init == null) {
1305
- this.logger.warn(`recoverSwaps(escrow): Fetched ${escrowHash} swap state, but swap not found locally!`);
1306
- continue;
1307
- }
1308
- }
1309
- else if (knownSwap instanceof IEscrowSwap_1.IEscrowSwap) {
1310
- this.logger.debug(`recoverSwaps(escrow): Forcibly updating ${escrowHash} swap: swap already known and in local storage!`);
1311
- if ((knownSwap._contractVersion ?? "v1") !== contractVersion) {
1312
- this.logger.debug(`recoverSwaps(escrow): Skipping ${escrowHash} swap: swap uses contract version ${knownSwap._contractVersion ?? "v1"}, but state comes from ${contractVersion}!`);
1313
- continue;
1314
- }
1315
- if (await knownSwap._forciblySetOnchainState(state)) {
1316
- await knownSwap._save();
1317
- }
1318
- continue;
1319
- }
1320
- else {
1321
- this.logger.debug(`recoverSwaps(escrow): Skipping ${escrowHash} swap: swap already known and in local storage!`);
1322
- continue;
1323
- }
1324
- const data = init.data;
1325
- //Classify swap
1326
- let swap;
1327
- let typeIdentified = false;
1328
- if (data.getType() === base_1.ChainSwapType.HTLC) {
1329
- if (data.isOfferer(signer)) {
1330
- //To BTCLN
1331
- typeIdentified = true;
1332
- const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isClaimer(val.getAddress(chainId)));
1333
- swap = await wrappers[SwapType_1.SwapType.TO_BTCLN].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1334
- }
1335
- else if (data.isClaimer(signer)) {
1336
- //From BTCLN
1337
- typeIdentified = true;
1338
- const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isOfferer(val.getAddress(chainId)));
1339
- if (swapContract.supportsInitWithoutClaimer && wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] != null) {
1340
- swap = await wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1341
- }
1342
- else {
1343
- swap = await wrappers[SwapType_1.SwapType.FROM_BTCLN].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1344
- }
1345
- }
1346
- }
1347
- else if (data.getType() === base_1.ChainSwapType.CHAIN_NONCED) {
1348
- //To BTC
1349
- typeIdentified = true;
1350
- const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isClaimer(val.getAddress(chainId)));
1351
- swap = await wrappers[SwapType_1.SwapType.TO_BTC].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1352
- }
1353
- else if (data.getType() === base_1.ChainSwapType.CHAIN) {
1354
- //From BTC
1355
- typeIdentified = true;
1356
- const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isOfferer(val.getAddress(chainId)));
1357
- swap = await wrappers[SwapType_1.SwapType.FROM_BTC].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1358
- }
1359
- if (swap != null) {
1360
- recoveredSwaps.push(swap);
1361
- }
1362
- else {
1363
- if (typeIdentified)
1364
- this.logger.debug(`recoverSwaps(escrow): Swap data type correctly identified but swap returned is null for swap ${escrowHash}`);
1365
- }
1366
- }
1367
- for (let contractVersion in recoveredSpvStates) {
1368
- const { spvVaultContract } = versionedContracts[contractVersion];
1369
- const spvVaultData = recoveredSpvStates[contractVersion];
1370
- const vaultsData = await spvVaultContract.getMultipleVaultData(Object.keys(spvVaultData)
1371
- .map(btcTxId => ({
1372
- owner: spvVaultData[btcTxId].owner,
1373
- vaultId: spvVaultData[btcTxId].vaultId
1374
- })));
1375
- for (let btcTxId in spvVaultData) {
1376
- const state = spvVaultData[btcTxId];
1377
- const knownSwap = knownSwaps[btcTxId];
1378
- if (knownSwap != null) {
1379
- if (knownSwap instanceof SpvFromBTCSwap_1.SpvFromBTCSwap) {
1380
- this.logger.debug(`recoverSwaps(spv_vault): Forcibly updating ${btcTxId} swap: swap already known and in local storage!`);
1381
- //TODO: Forcibly set on-chain state to the swap
1382
- // if(await knownSwap._forciblySetOnchainState(state)) {
1383
- // await knownSwap._save();
1384
- // }
1385
- continue;
1386
- }
1387
- else {
1388
- this.logger.debug(`recoverSwaps(spv_vault): Skipping ${btcTxId} swap: swap already known and in local storage!`);
1389
- continue;
1390
- }
1391
- }
1392
- const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && state.owner.toLowerCase() === val.getAddress(chainId).toLowerCase());
1393
- const swap = await wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC].recoverFromState(state, contractVersion, vaultsData[state.owner]?.[state.vaultId.toString(10)], lp);
1394
- if (swap != null) {
1395
- recoveredSwaps.push(swap);
1396
- }
1397
- else {
1398
- this.logger.debug(`recoverSwaps(spv_vault): Swap data type correctly identified but swap returned is null for swap ${btcTxId}`);
1399
- }
1400
- }
1401
- }
1402
- this.logger.debug(`recoverSwaps(): Successfully recovered ${recoveredSwaps.length} swaps!`);
1403
- return recoveredSwaps;
1404
- }
1405
- /**
1406
- * Returns the {@link Token} object for a given token
1407
- *
1408
- * @param tickerOrAddress Token to return the object for, can use multiple formats:
1409
- * - a) token ticker, such as `"BTC"`, `"SOL"`, etc.
1410
- * - b) token ticker prefixed with smart chain identifier, such as `"SOLANA-SOL"`, `"SOLANA-USDC"`, etc.
1411
- * - c) token address
1412
- */
1413
- getToken(tickerOrAddress) {
1414
- //Btc tokens - BTC, BTCLN, BTC-LN
1415
- if (tickerOrAddress === "BTC" || tickerOrAddress === "BITCOIN-BTC")
1416
- return Token_1.BitcoinTokens.BTC;
1417
- if (tickerOrAddress === "BTCLN" || tickerOrAddress === "BTC-LN" || tickerOrAddress === "LIGHTNING-BTC")
1418
- return Token_1.BitcoinTokens.BTCLN;
1419
- //Check if the ticker is in format <chainId>-<ticker>, i.e. SOLANA-USDC, STARKNET-WBTC
1420
- if (tickerOrAddress.includes("-")) {
1421
- const [chainId, ticker] = tickerOrAddress.split("-");
1422
- const token = this._tokensByTicker[chainId]?.[ticker];
1423
- if (token == null)
1424
- throw new UserError_1.UserError(`Not found ticker: ${ticker} for chainId: ${chainId}`);
1425
- return token;
1426
- }
1427
- const possibleTokens = [];
1428
- for (let chainId in this._chains) {
1429
- const chain = this._chains[chainId];
1430
- if (chain.chainInterface.isValidToken(tickerOrAddress)) {
1431
- //Try to find in known token addresses
1432
- const token = this._tokens[chainId]?.[tickerOrAddress];
1433
- if (token != null)
1434
- return token;
1435
- }
1436
- else {
1437
- //Check in known tickers
1438
- const token = this._tokensByTicker[chainId]?.[tickerOrAddress];
1439
- if (token != null)
1440
- possibleTokens.push(token);
1441
- }
1442
- }
1443
- if (possibleTokens.length === 0)
1444
- throw new UserError_1.UserError(`Specified token address or ticker ${tickerOrAddress} not found!`);
1445
- //In case we've found the token in multiple chains
1446
- if (possibleTokens.length > 1)
1447
- throw new UserError_1.UserError(`A ticker ${tickerOrAddress} has been found in multiple chains, narrow it down by using <chainId>-${tickerOrAddress} notation`);
1448
- return possibleTokens[0];
1449
- }
1450
- /**
1451
- * Creates a child swapper instance with a given smart chain
1452
- *
1453
- * @param chainIdentifier Smart chain identifier for the created child swapper instance
1454
- */
1455
- withChain(chainIdentifier) {
1456
- if (this._chains[chainIdentifier] == null)
1457
- throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
1458
- return new SwapperWithChain_1.SwapperWithChain(this, chainIdentifier);
1459
- }
1460
- /**
1461
- * Returns an array of all the supported smart chains
1462
- */
1463
- getSmartChains() {
1464
- return Object.keys(this._chains);
1465
- }
1466
- /**
1467
- * Returns whether the SDK supports a given swap type on a given chain based on currently known LPs
1468
- *
1469
- * @param chainId Smart chain identifier string
1470
- * @param swapType Swap protocol type
1471
- */
1472
- supportsSwapType(chainId, swapType) {
1473
- return (this._chains[chainId]?.wrappers[swapType] != null);
1474
- }
1475
- /**
1476
- * Returns type of the swap based on input and output tokens specified
1477
- *
1478
- * @param srcToken Source token
1479
- * @param dstToken Destination token
1480
- */
1481
- getSwapType(srcToken, dstToken) {
1482
- if ((0, Token_1.isSCToken)(srcToken)) {
1483
- if (!(0, Token_1.isBtcToken)(dstToken))
1484
- throw new Error("Swap not supported");
1485
- if (dstToken.lightning) {
1486
- return SwapType_1.SwapType.TO_BTCLN;
1487
- }
1488
- else {
1489
- return SwapType_1.SwapType.TO_BTC;
1490
- }
1491
- }
1492
- else if ((0, Token_1.isBtcToken)(srcToken)) {
1493
- if (!(0, Token_1.isSCToken)(dstToken))
1494
- throw new Error("Swap not supported");
1495
- if (srcToken.lightning) {
1496
- if (this.supportsSwapType(dstToken.chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO)) {
1497
- return SwapType_1.SwapType.FROM_BTCLN_AUTO;
1498
- }
1499
- else {
1500
- return SwapType_1.SwapType.FROM_BTCLN;
1501
- }
1502
- }
1503
- else {
1504
- if (this.supportsSwapType(dstToken.chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC)) {
1505
- return SwapType_1.SwapType.SPV_VAULT_FROM_BTC;
1506
- }
1507
- else {
1508
- return SwapType_1.SwapType.FROM_BTC;
1509
- }
1510
- }
1511
- }
1512
- throw new Error("Swap not supported");
1513
- }
1514
- /**
1515
- * Returns minimum/maximum limits for inputs and outputs for a swap between given tokens
1516
- *
1517
- * @param srcToken Source token
1518
- * @param dstToken Destination token
1519
- */
1520
- getSwapLimits(srcToken, dstToken) {
1521
- const swapType = this.getSwapType(srcToken, dstToken);
1522
- const scToken = (0, Token_1.isSCToken)(srcToken) ? srcToken : (0, Token_1.isSCToken)(dstToken) ? dstToken : null;
1523
- if (scToken == null)
1524
- throw new Error("At least one token needs to be a smart chain token!");
1525
- const result = {
1526
- input: {},
1527
- output: {}
1528
- };
1529
- for (let lp of this.intermediaryDiscovery.intermediaries) {
1530
- const lpMinMax = lp.getSwapLimits(swapType, scToken.chainId, scToken.address);
1531
- if (lpMinMax == null)
1532
- continue;
1533
- result.input.min = result.input.min == null ? lpMinMax.input.min : (0, Utils_1.bigIntMin)(result.input.min, lpMinMax.input.min);
1534
- result.input.max = result.input.max == null ? lpMinMax.input.max : (0, Utils_1.bigIntMax)(result.input.max, lpMinMax.input.max);
1535
- result.output.min = result.output.min == null ? lpMinMax.output.min : (0, Utils_1.bigIntMin)(result.output.min, lpMinMax.output.min);
1536
- result.output.max = result.output.max == null ? lpMinMax.output.max : (0, Utils_1.bigIntMax)(result.output.max, lpMinMax.output.max);
1537
- }
1538
- return {
1539
- input: {
1540
- min: (0, TokenAmount_1.toTokenAmount)(result.input.min ?? 1n, srcToken, this.prices),
1541
- max: result.input.max == null ? undefined : (0, TokenAmount_1.toTokenAmount)(result.input.max, srcToken, this.prices),
1542
- },
1543
- output: {
1544
- min: (0, TokenAmount_1.toTokenAmount)(result.output.min ?? 1n, dstToken, this.prices),
1545
- max: result.output.max == null ? undefined : (0, TokenAmount_1.toTokenAmount)(result.output.max, dstToken, this.prices),
1546
- }
1547
- };
1548
- }
1549
- /**
1550
- * Returns an array of supported tokens either on the input or on the output of a swap
1551
- *
1552
- * @param input Whether to return input tokens or output tokens
1553
- */
1554
- getSupportedTokens(input) {
1555
- const tokens = {};
1556
- let lightning = false;
1557
- let btc = false;
1558
- this.intermediaryDiscovery.intermediaries.forEach(lp => {
1559
- for (let swapType of [SwapType_1.SwapType.TO_BTC, SwapType_1.SwapType.TO_BTCLN, SwapType_1.SwapType.FROM_BTC, SwapType_1.SwapType.FROM_BTCLN, SwapType_1.SwapType.SPV_VAULT_FROM_BTC, SwapType_1.SwapType.FROM_BTCLN_AUTO]) {
1560
- if (lp.services[swapType]?.chainTokens == null)
1561
- continue;
1562
- for (let chainId of this.getSmartChains()) {
1563
- if (this.supportsSwapType(chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC) ? swapType === SwapType_1.SwapType.FROM_BTC : swapType === SwapType_1.SwapType.SPV_VAULT_FROM_BTC)
1564
- continue;
1565
- if (this.supportsSwapType(chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO) ? swapType === SwapType_1.SwapType.FROM_BTCLN : swapType === SwapType_1.SwapType.FROM_BTCLN_AUTO)
1566
- continue;
1567
- const chainTokens = lp.services[swapType]?.chainTokens?.[chainId];
1568
- if (chainTokens == null)
1569
- continue;
1570
- for (let tokenAddress of chainTokens) {
1571
- if (input) {
1572
- if (swapType === SwapType_1.SwapType.TO_BTC || swapType === SwapType_1.SwapType.TO_BTCLN) {
1573
- tokens[chainId] ??= new Set();
1574
- tokens[chainId].add(tokenAddress);
1575
- }
1576
- if (swapType === SwapType_1.SwapType.FROM_BTCLN || swapType === SwapType_1.SwapType.FROM_BTCLN_AUTO) {
1577
- lightning = true;
1578
- }
1579
- if (swapType === SwapType_1.SwapType.FROM_BTC || swapType === SwapType_1.SwapType.SPV_VAULT_FROM_BTC) {
1580
- btc = true;
1581
- }
1582
- }
1583
- else {
1584
- if (swapType === SwapType_1.SwapType.FROM_BTCLN || swapType === SwapType_1.SwapType.FROM_BTC || swapType === SwapType_1.SwapType.SPV_VAULT_FROM_BTC || swapType === SwapType_1.SwapType.FROM_BTCLN_AUTO) {
1585
- tokens[chainId] ??= new Set();
1586
- tokens[chainId].add(tokenAddress);
1587
- }
1588
- if (swapType === SwapType_1.SwapType.TO_BTCLN) {
1589
- lightning = true;
1590
- }
1591
- if (swapType === SwapType_1.SwapType.TO_BTC) {
1592
- btc = true;
1593
- }
1594
- }
1595
- }
1596
- }
1597
- }
1598
- });
1599
- const output = [];
1600
- if (lightning)
1601
- output.push(Token_1.BitcoinTokens.BTCLN);
1602
- if (btc)
1603
- output.push(Token_1.BitcoinTokens.BTC);
1604
- for (let chainId in tokens) {
1605
- tokens[chainId].forEach(tokenAddress => {
1606
- const token = this._tokens?.[chainId]?.[tokenAddress];
1607
- if (token != null)
1608
- output.push(token);
1609
- });
1610
- }
1611
- return output;
1612
- }
1613
- /**
1614
- * Returns a set of supported tokens by all the intermediaries offering a specific swap service
1615
- *
1616
- * @param _swapType Swap service type to check supported tokens for
1617
- */
1618
- getSupportedTokensForSwapType(_swapType) {
1619
- const tokens = {};
1620
- this.intermediaryDiscovery.intermediaries.forEach(lp => {
1621
- for (let chainId of this.getSmartChains()) {
1622
- let swapType = _swapType;
1623
- if (swapType === SwapType_1.SwapType.FROM_BTC && this.supportsSwapType(chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC))
1624
- swapType = SwapType_1.SwapType.SPV_VAULT_FROM_BTC;
1625
- if (swapType === SwapType_1.SwapType.FROM_BTCLN && this.supportsSwapType(chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO))
1626
- swapType = SwapType_1.SwapType.FROM_BTCLN_AUTO;
1627
- if (lp.services[swapType]?.chainTokens == null)
1628
- break;
1629
- const chainTokens = lp.services[swapType]?.chainTokens?.[chainId];
1630
- if (chainTokens == null)
1631
- continue;
1632
- for (let tokenAddress of chainTokens) {
1633
- tokens[chainId] ??= new Set();
1634
- tokens[chainId].add(tokenAddress);
1635
- }
1636
- }
1637
- });
1638
- const output = [];
1639
- for (let chainId in tokens) {
1640
- tokens[chainId].forEach(tokenAddress => {
1641
- const token = this._tokens?.[chainId]?.[tokenAddress];
1642
- if (token != null)
1643
- output.push(token);
1644
- });
1645
- }
1646
- return output;
1647
- }
1648
- /**
1649
- * Returns the set of supported token addresses by all the intermediaries we know of offering a specific swapType service
1650
- *
1651
- * @param chainIdentifier Chain identifier string
1652
- * @param swapType Specific swap type for which to obtain supported tokens
1653
- */
1654
- getSupportedTokenAddresses(chainIdentifier, swapType) {
1655
- const set = new Set();
1656
- this.intermediaryDiscovery.intermediaries.forEach(lp => {
1657
- const chainTokens = lp.services[swapType]?.chainTokens?.[chainIdentifier];
1658
- if (chainTokens == null)
1659
- return;
1660
- chainTokens.forEach(token => set.add(token));
1661
- });
1662
- return set;
1663
- }
1664
- /**
1665
- * Returns tokens that you can swap to (if input=true) from a given token,
1666
- * or tokens that you can swap from (if input=false) to a given token
1667
- */
1668
- getSwapCounterTokens(token, input) {
1669
- if ((0, Token_1.isSCToken)(token)) {
1670
- const result = [];
1671
- if (input) {
1672
- //TO_BTC or TO_BTCLN
1673
- if (this.getSupportedTokenAddresses(token.chainId, SwapType_1.SwapType.TO_BTCLN).has(token.address)) {
1674
- result.push(Token_1.BitcoinTokens.BTCLN);
1675
- }
1676
- if (this.getSupportedTokenAddresses(token.chainId, SwapType_1.SwapType.TO_BTC).has(token.address)) {
1677
- result.push(Token_1.BitcoinTokens.BTC);
1678
- }
1679
- }
1680
- else {
1681
- //FROM_BTC or FROM_BTCLN
1682
- const fromLightningSwapType = this.supportsSwapType(token.chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO) ? SwapType_1.SwapType.FROM_BTCLN_AUTO : SwapType_1.SwapType.FROM_BTCLN;
1683
- if (this.getSupportedTokenAddresses(token.chainId, fromLightningSwapType).has(token.address)) {
1684
- result.push(Token_1.BitcoinTokens.BTCLN);
1685
- }
1686
- const fromOnchainSwapType = this.supportsSwapType(token.chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC) ? SwapType_1.SwapType.SPV_VAULT_FROM_BTC : SwapType_1.SwapType.FROM_BTC;
1687
- if (this.getSupportedTokenAddresses(token.chainId, fromOnchainSwapType).has(token.address)) {
1688
- result.push(Token_1.BitcoinTokens.BTC);
1689
- }
1690
- }
1691
- return result;
1692
- }
1693
- else {
1694
- if (input) {
1695
- if (token.lightning) {
1696
- return this.getSupportedTokensForSwapType(SwapType_1.SwapType.FROM_BTCLN);
1697
- }
1698
- else {
1699
- return this.getSupportedTokensForSwapType(SwapType_1.SwapType.FROM_BTC);
1700
- }
1701
- }
1702
- else {
1703
- if (token.lightning) {
1704
- return this.getSupportedTokensForSwapType(SwapType_1.SwapType.TO_BTCLN);
1705
- }
1706
- else {
1707
- return this.getSupportedTokensForSwapType(SwapType_1.SwapType.TO_BTC);
1708
- }
1709
- }
1710
- }
1711
- }
1712
- }
1713
- exports.Swapper = Swapper;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Swapper = void 0;
4
+ const base_1 = require("@atomiqlabs/base");
5
+ const ToBTCLNWrapper_1 = require("../swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper");
6
+ const ToBTCWrapper_1 = require("../swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper");
7
+ const FromBTCLNWrapper_1 = require("../swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper");
8
+ const FromBTCWrapper_1 = require("../swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper");
9
+ const IntermediaryDiscovery_1 = require("../intermediaries/IntermediaryDiscovery");
10
+ const bolt11_1 = require("@atomiqlabs/bolt11");
11
+ const IntermediaryError_1 = require("../errors/IntermediaryError");
12
+ const SwapType_1 = require("../enums/SwapType");
13
+ const LnForGasWrapper_1 = require("../swaps/trusted/ln/LnForGasWrapper");
14
+ const events_1 = require("events");
15
+ const Utils_1 = require("../utils/Utils");
16
+ const RequestError_1 = require("../errors/RequestError");
17
+ const SwapperWithChain_1 = require("./SwapperWithChain");
18
+ const OnchainForGasWrapper_1 = require("../swaps/trusted/onchain/OnchainForGasWrapper");
19
+ const utils_1 = require("@scure/btc-signer/utils");
20
+ const UnifiedSwapStorage_1 = require("../storage/UnifiedSwapStorage");
21
+ const UnifiedSwapEventListener_1 = require("../events/UnifiedSwapEventListener");
22
+ const SpvFromBTCWrapper_1 = require("../swaps/spv_swaps/SpvFromBTCWrapper");
23
+ const SpvFromBTCSwap_1 = require("../swaps/spv_swaps/SpvFromBTCSwap");
24
+ const SwapperUtils_1 = require("./SwapperUtils");
25
+ const FromBTCLNAutoWrapper_1 = require("../swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper");
26
+ const UserError_1 = require("../errors/UserError");
27
+ const AutomaticClockDriftCorrection_1 = require("../utils/AutomaticClockDriftCorrection");
28
+ const SwapUtils_1 = require("../utils/SwapUtils");
29
+ const IndexedDBUnifiedStorage_1 = require("../storage-browser/IndexedDBUnifiedStorage");
30
+ const TokenAmount_1 = require("../types/TokenAmount");
31
+ const Token_1 = require("../types/Token");
32
+ const Logger_1 = require("../utils/Logger");
33
+ const LNURLWithdraw_1 = require("../types/lnurl/LNURLWithdraw");
34
+ const LNURLPay_1 = require("../types/lnurl/LNURLPay");
35
+ const RetryUtils_1 = require("../utils/RetryUtils");
36
+ const IEscrowSwap_1 = require("../swaps/escrow_swaps/IEscrowSwap");
37
+ const LightningInvoiceCreateService_1 = require("../types/wallets/LightningInvoiceCreateService");
38
+ const BitcoinWalletUtils_1 = require("../utils/BitcoinWalletUtils");
39
+ /**
40
+ * Core orchestrator for all atomiq swap operations
41
+ *
42
+ * @category Core
43
+ */
44
+ class Swapper extends events_1.EventEmitter {
45
+ /**
46
+ * @internal
47
+ */
48
+ constructor(bitcoinRpc, lightningApi, bitcoinSynchronizer, chainsData, pricing, tokens, messenger, options) {
49
+ super();
50
+ this.logger = (0, Logger_1.getLogger)(this.constructor.name + ": ");
51
+ this.initialized = false;
52
+ /**
53
+ * Helper information about various swap protocol and their features:
54
+ * - `requiresInputWallet`: Whether a swap requires a connected wallet on the input chain able to sign
55
+ * arbitrary transaction
56
+ * - `requiresOutputWallet`: Whether a swap requires a connected wallet on the output chain able to sign
57
+ * arbitrary transactions
58
+ * - `supportsGasDrop`: Whether a swap supports the "gas drop" feature, allowing to user to receive a small
59
+ * amount of native token as part of the swap when swapping to smart chains
60
+ *
61
+ * Uses a `Record` type here, use the {@link SwapProtocolInfo} import for a literal readonly type, with
62
+ * pre-filled exact values in the type.
63
+ */
64
+ this.SwapTypeInfo = SwapUtils_1.SwapProtocolInfo;
65
+ const storagePrefix = options?.storagePrefix ?? "atomiq-";
66
+ options ??= {};
67
+ options.saveUninitializedSwaps ??= true;
68
+ options.bitcoinNetwork = options.bitcoinNetwork == null ? base_1.BitcoinNetwork.TESTNET : options.bitcoinNetwork;
69
+ const swapStorage = options.swapStorage ??= (name) => new IndexedDBUnifiedStorage_1.IndexedDBUnifiedStorage(name);
70
+ this.options = options;
71
+ this.bitcoinNetwork = options.bitcoinNetwork;
72
+ this._btcNetwork = options.bitcoinNetwork === base_1.BitcoinNetwork.MAINNET ? utils_1.NETWORK :
73
+ (options.bitcoinNetwork === base_1.BitcoinNetwork.TESTNET || options.bitcoinNetwork === base_1.BitcoinNetwork.TESTNET4) ? utils_1.TEST_NETWORK : {
74
+ bech32: 'bcrt',
75
+ pubKeyHash: 111,
76
+ scriptHash: 196,
77
+ wif: 239
78
+ };
79
+ this.Utils = new SwapperUtils_1.SwapperUtils(this);
80
+ this.prices = pricing;
81
+ this._bitcoinRpc = bitcoinRpc;
82
+ this.messenger = messenger;
83
+ this._tokens = {};
84
+ this._tokensByTicker = {};
85
+ for (let tokenData of tokens) {
86
+ const chainId = tokenData.chainId;
87
+ this._tokens[chainId] ??= {};
88
+ this._tokensByTicker[chainId] ??= {};
89
+ this._tokens[chainId][tokenData.address] = this._tokensByTicker[chainId][tokenData.ticker] = tokenData;
90
+ }
91
+ this.swapStateListener = (swap) => {
92
+ this.emit("swapState", swap);
93
+ };
94
+ this._chains = (0, Utils_1.objectMap)(chainsData, (chainData, key) => {
95
+ let { chainInterface, chainEvents, chainId, btcRelay, swapContract, swapDataConstructor, spvVaultContract, spvVaultWithdrawalDataConstructor, spvVaultDataConstructor, defaultVersion, versions } = chainData;
96
+ defaultVersion ??= "v1";
97
+ if (versions == null) {
98
+ versions = {
99
+ [defaultVersion]: {
100
+ btcRelay,
101
+ swapContract,
102
+ swapDataConstructor,
103
+ spvVaultContract,
104
+ spvVaultDataConstructor,
105
+ spvVaultWithdrawalDataConstructor
106
+ }
107
+ };
108
+ }
109
+ const versionedContracts = (0, Utils_1.objectMap)(versions, (value, key) => {
110
+ return {
111
+ swapContract: value.swapContract,
112
+ spvVaultContract: value.spvVaultContract,
113
+ btcRelay: value.btcRelay,
114
+ synchronizer: bitcoinSynchronizer(value.btcRelay)
115
+ };
116
+ });
117
+ const storageHandler = swapStorage(storagePrefix + chainId);
118
+ const unifiedSwapStorage = new UnifiedSwapStorage_1.UnifiedSwapStorage(storageHandler, this.options.noSwapCache);
119
+ const unifiedChainEvents = new UnifiedSwapEventListener_1.UnifiedSwapEventListener(unifiedSwapStorage, chainEvents);
120
+ const wrappers = {};
121
+ wrappers[SwapType_1.SwapType.TO_BTCLN] = new ToBTCLNWrapper_1.ToBTCLNWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, {
122
+ getRequestTimeout: this.options.getRequestTimeout,
123
+ postRequestTimeout: this.options.postRequestTimeout,
124
+ saveUninitializedSwaps: this.options.saveUninitializedSwaps,
125
+ });
126
+ wrappers[SwapType_1.SwapType.TO_BTC] = new ToBTCWrapper_1.ToBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, this._bitcoinRpc, {
127
+ getRequestTimeout: this.options.getRequestTimeout,
128
+ postRequestTimeout: this.options.postRequestTimeout,
129
+ saveUninitializedSwaps: this.options.saveUninitializedSwaps,
130
+ bitcoinNetwork: this._btcNetwork
131
+ });
132
+ wrappers[SwapType_1.SwapType.FROM_BTCLN] = new FromBTCLNWrapper_1.FromBTCLNWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, lightningApi, {
133
+ getRequestTimeout: this.options.getRequestTimeout,
134
+ postRequestTimeout: this.options.postRequestTimeout,
135
+ saveUninitializedSwaps: this.options.saveUninitializedSwaps,
136
+ unsafeSkipLnNodeCheck: this.bitcoinNetwork === base_1.BitcoinNetwork.TESTNET4 || this.bitcoinNetwork === base_1.BitcoinNetwork.REGTEST
137
+ });
138
+ wrappers[SwapType_1.SwapType.FROM_BTC] = new FromBTCWrapper_1.FromBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, versionedContracts, this._bitcoinRpc, {
139
+ getRequestTimeout: this.options.getRequestTimeout,
140
+ postRequestTimeout: this.options.postRequestTimeout,
141
+ saveUninitializedSwaps: this.options.saveUninitializedSwaps,
142
+ bitcoinNetwork: this._btcNetwork
143
+ });
144
+ wrappers[SwapType_1.SwapType.TRUSTED_FROM_BTCLN] = new LnForGasWrapper_1.LnForGasWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], {
145
+ getRequestTimeout: this.options.getRequestTimeout,
146
+ postRequestTimeout: this.options.postRequestTimeout,
147
+ saveUninitializedSwaps: this.options.saveUninitializedSwaps,
148
+ });
149
+ wrappers[SwapType_1.SwapType.TRUSTED_FROM_BTC] = new OnchainForGasWrapper_1.OnchainForGasWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], bitcoinRpc, {
150
+ getRequestTimeout: this.options.getRequestTimeout,
151
+ postRequestTimeout: this.options.postRequestTimeout,
152
+ saveUninitializedSwaps: this.options.saveUninitializedSwaps,
153
+ bitcoinNetwork: this._btcNetwork
154
+ });
155
+ // This is gated on the default version of the contracts
156
+ if (spvVaultContract != null) {
157
+ wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC] = new SpvFromBTCWrapper_1.SpvFromBTCWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, versionedContracts, bitcoinRpc, {
158
+ getRequestTimeout: this.options.getRequestTimeout,
159
+ postRequestTimeout: this.options.postRequestTimeout,
160
+ saveUninitializedSwaps: this.options.saveUninitializedSwaps,
161
+ bitcoinNetwork: this._btcNetwork
162
+ });
163
+ }
164
+ // This is gated on the default version of the contracts
165
+ if (swapContract.supportsInitWithoutClaimer) {
166
+ wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] = new FromBTCLNAutoWrapper_1.FromBTCLNAutoWrapper(key, unifiedSwapStorage, unifiedChainEvents, chainInterface, pricing, this._tokens[chainId], versions, lightningApi, this.messenger, {
167
+ getRequestTimeout: this.options.getRequestTimeout,
168
+ postRequestTimeout: this.options.postRequestTimeout,
169
+ saveUninitializedSwaps: this.options.saveUninitializedSwaps,
170
+ unsafeSkipLnNodeCheck: this.bitcoinNetwork === base_1.BitcoinNetwork.TESTNET4 || this.bitcoinNetwork === base_1.BitcoinNetwork.REGTEST
171
+ });
172
+ }
173
+ Object.keys(wrappers).forEach(key => wrappers[key].events.on("swapState", this.swapStateListener));
174
+ const reviver = (val) => {
175
+ const wrapper = wrappers[val.type];
176
+ if (wrapper == null)
177
+ return null;
178
+ return new wrapper._swapDeserializer(wrapper, val);
179
+ };
180
+ return {
181
+ chainEvents,
182
+ chainInterface,
183
+ wrappers,
184
+ unifiedChainEvents,
185
+ unifiedSwapStorage,
186
+ defaultVersion,
187
+ reviver,
188
+ versionedContracts
189
+ };
190
+ });
191
+ const contracts = (0, Utils_1.objectMap)(chainsData, (data) => data.versions ?? { [data.defaultVersion ?? "v1"]: { swapContract: data.swapContract, spvVaultContract: data.spvVaultContract } });
192
+ if (options.intermediaryUrl != null) {
193
+ this.intermediaryDiscovery = new IntermediaryDiscovery_1.IntermediaryDiscovery(contracts, options.registryUrl, Array.isArray(options.intermediaryUrl) ? options.intermediaryUrl : [options.intermediaryUrl], options.getRequestTimeout);
194
+ }
195
+ else {
196
+ this.intermediaryDiscovery = new IntermediaryDiscovery_1.IntermediaryDiscovery(contracts, options.registryUrl, undefined, options.getRequestTimeout);
197
+ }
198
+ this.intermediaryDiscovery.on("removed", (intermediaries) => {
199
+ this.emit("lpsRemoved", intermediaries);
200
+ });
201
+ this.intermediaryDiscovery.on("added", (intermediaries) => {
202
+ this.emit("lpsAdded", intermediaries);
203
+ });
204
+ }
205
+ async _init() {
206
+ this.logger.debug("init(): Initializing swapper...");
207
+ const abortController = new AbortController();
208
+ const promises = [];
209
+ let automaticClockDriftCorrectionPromise = undefined;
210
+ if (this.options.automaticClockDriftCorrection) {
211
+ promises.push(automaticClockDriftCorrectionPromise = (0, RetryUtils_1.tryWithRetries)(AutomaticClockDriftCorrection_1.correctClock, undefined, undefined, abortController.signal).catch((err) => {
212
+ abortController.abort(err);
213
+ }));
214
+ }
215
+ this.logger.debug("init(): Initializing intermediary discovery");
216
+ if (!this.options.dontFetchLPs)
217
+ promises.push(this.intermediaryDiscovery.init(abortController.signal).catch(err => {
218
+ if (abortController.signal.aborted)
219
+ return;
220
+ this.logger.error("init(): Failed to fetch intermediaries/LPs: ", err);
221
+ }));
222
+ if (this.options.defaultTrustedIntermediaryUrl != null) {
223
+ promises.push(this.intermediaryDiscovery.getIntermediary(this.options.defaultTrustedIntermediaryUrl, abortController.signal)
224
+ .then(val => {
225
+ if (val == null)
226
+ throw new Error("Cannot get trusted LP");
227
+ this.defaultTrustedIntermediary = val;
228
+ })
229
+ .catch(err => {
230
+ if (abortController.signal.aborted)
231
+ return;
232
+ this.logger.error("init(): Failed to contact trusted LP url: ", err);
233
+ }));
234
+ }
235
+ if (automaticClockDriftCorrectionPromise != null) {
236
+ //We should await the promises here before checking the swaps
237
+ await automaticClockDriftCorrectionPromise;
238
+ }
239
+ const chainPromises = [];
240
+ for (let chainIdentifier in this._chains) {
241
+ chainPromises.push((async () => {
242
+ const { chainInterface, versionedContracts, unifiedChainEvents, unifiedSwapStorage, wrappers, reviver } = this._chains[chainIdentifier];
243
+ const _chainInterface = chainInterface;
244
+ if (_chainInterface.verifyNetwork != null) {
245
+ await _chainInterface.verifyNetwork(this.bitcoinNetwork);
246
+ }
247
+ for (let contractVersion in versionedContracts) {
248
+ await versionedContracts[contractVersion].swapContract.start();
249
+ this.logger.debug("init(): Intialized swap contract: " + chainIdentifier + ` version: ${contractVersion}`);
250
+ }
251
+ await unifiedSwapStorage.init();
252
+ if (unifiedSwapStorage.storage instanceof IndexedDBUnifiedStorage_1.IndexedDBUnifiedStorage) {
253
+ //Try to migrate the data here
254
+ const storagePrefix = chainIdentifier === "SOLANA" ?
255
+ "SOLv4-" + this.bitcoinNetwork + "-Swaps-" :
256
+ "atomiqsdk-" + this.bitcoinNetwork + chainIdentifier + "-Swaps-";
257
+ await unifiedSwapStorage.storage.tryMigrate([
258
+ [storagePrefix + "FromBTC", SwapType_1.SwapType.FROM_BTC],
259
+ [storagePrefix + "FromBTCLN", SwapType_1.SwapType.FROM_BTCLN],
260
+ [storagePrefix + "ToBTC", SwapType_1.SwapType.TO_BTC],
261
+ [storagePrefix + "ToBTCLN", SwapType_1.SwapType.TO_BTCLN]
262
+ ], (obj) => {
263
+ const swap = reviver(obj);
264
+ if (swap._randomNonce == null) {
265
+ const oldIdentifierHash = swap.getId();
266
+ swap._randomNonce = (0, Utils_1.randomBytes)(16).toString("hex");
267
+ const newIdentifierHash = swap.getId();
268
+ this.logger.info("init(): Found older swap version without randomNonce, replacing, old hash: " + oldIdentifierHash +
269
+ " new hash: " + newIdentifierHash);
270
+ }
271
+ return swap;
272
+ });
273
+ }
274
+ if (!this.options.noEvents)
275
+ await unifiedChainEvents.start();
276
+ this.logger.debug("init(): Intialized events: " + chainIdentifier);
277
+ for (let key in wrappers) {
278
+ // this.logger.debug("init(): Initializing "+SwapType[key]+": "+chainIdentifier);
279
+ await wrappers[key].init(this.options.noTimers, this.options.dontCheckPastSwaps);
280
+ }
281
+ })());
282
+ }
283
+ await Promise.all(chainPromises);
284
+ await Promise.all(promises);
285
+ this.logger.debug("init(): Initializing messenger");
286
+ await this.messenger.init();
287
+ }
288
+ /**
289
+ * Initializes the swap storage and loads existing swaps, needs to be called before any other action
290
+ */
291
+ async init() {
292
+ if (this.initialized)
293
+ return;
294
+ if (this.initPromise != null) {
295
+ await this.initPromise;
296
+ return;
297
+ }
298
+ try {
299
+ const promise = this._init();
300
+ this.initPromise = promise;
301
+ await promise;
302
+ delete this.initPromise;
303
+ this.initialized = true;
304
+ }
305
+ catch (e) {
306
+ delete this.initPromise;
307
+ throw e;
308
+ }
309
+ }
310
+ /**
311
+ * Stops listening for onchain events and closes this Swapper instance
312
+ */
313
+ async stop() {
314
+ if (this.initPromise)
315
+ await this.initPromise;
316
+ for (let chainIdentifier in this._chains) {
317
+ const { wrappers, unifiedChainEvents } = this._chains[chainIdentifier];
318
+ for (let key in wrappers) {
319
+ const wrapper = wrappers[key];
320
+ wrapper.events.removeListener("swapState", this.swapStateListener);
321
+ await wrapper.stop();
322
+ }
323
+ await unifiedChainEvents.stop();
324
+ await this.messenger.stop();
325
+ }
326
+ this.initialized = false;
327
+ }
328
+ /**
329
+ * Creates swap & handles intermediary, quote selection
330
+ *
331
+ * @param chainIdentifier
332
+ * @param create Callback to create the
333
+ * @param amountData Amount data as passed to the function
334
+ * @param swapType Swap type of the execution
335
+ * @param maxWaitTimeMS Maximum waiting time after the first intermediary returns the quote
336
+ * @private
337
+ * @throws {Error} when no intermediary was found
338
+ * @throws {Error} if the chain with the provided identifier cannot be found
339
+ */
340
+ async createSwap(chainIdentifier, create, amountData, swapType, maxWaitTimeMS = 2000) {
341
+ if (!this.initialized)
342
+ throw new Error("Swapper not initialized, init first with swapper.init()!");
343
+ if (this._chains[chainIdentifier] == null)
344
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
345
+ let candidates;
346
+ const inBtc = swapType === SwapType_1.SwapType.TO_BTCLN || swapType === SwapType_1.SwapType.TO_BTC ? !amountData.exactIn : amountData.exactIn;
347
+ if (!inBtc || amountData.amount == null) {
348
+ //Get candidates not based on the amount
349
+ candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token);
350
+ }
351
+ else {
352
+ candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token, amountData.amount);
353
+ }
354
+ let swapLimitsChanged = false;
355
+ if (candidates.length === 0) {
356
+ this.logger.warn("createSwap(): No valid intermediary found to execute the swap with, reloading intermediary database...");
357
+ await this.intermediaryDiscovery.reloadIntermediaries();
358
+ swapLimitsChanged = true;
359
+ if (!inBtc || amountData.amount == null) {
360
+ //Get candidates not based on the amount
361
+ candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token);
362
+ }
363
+ else {
364
+ candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token, amountData.amount);
365
+ if (candidates.length === 0) {
366
+ const min = this.intermediaryDiscovery.getSwapMinimum(chainIdentifier, swapType, amountData.token);
367
+ const max = this.intermediaryDiscovery.getSwapMaximum(chainIdentifier, swapType, amountData.token);
368
+ if (min != null && max != null) {
369
+ if (amountData.amount < BigInt(min))
370
+ throw new RequestError_1.OutOfBoundsError("Swap amount too low! Try swapping a higher amount.", 200, BigInt(min), BigInt(max));
371
+ if (amountData.amount > BigInt(max))
372
+ throw new RequestError_1.OutOfBoundsError("Swap amount too high! Try swapping a lower amount.", 200, BigInt(min), BigInt(max));
373
+ }
374
+ }
375
+ }
376
+ if (candidates.length === 0)
377
+ throw new Error("No intermediary found for the requested pair and amount! You can try swapping different pair or higher/lower amount.");
378
+ }
379
+ const abortController = new AbortController();
380
+ this.logger.debug("createSwap() Swap candidates: ", candidates.map(lp => lp.url).join());
381
+ const quotePromises = await create(candidates, abortController.signal, this._chains[chainIdentifier]);
382
+ const promiseAll = new Promise((resolve, reject) => {
383
+ let min;
384
+ let max;
385
+ let error;
386
+ let numResolved = 0;
387
+ let quotes = [];
388
+ let timeout;
389
+ quotePromises.forEach(data => {
390
+ data.quote.then(quote => {
391
+ if (numResolved === 0) {
392
+ timeout = setTimeout(() => {
393
+ abortController.abort(new Error("Timed out waiting for quote!"));
394
+ resolve(quotes);
395
+ }, maxWaitTimeMS);
396
+ }
397
+ numResolved++;
398
+ quotes.push({
399
+ quote,
400
+ intermediary: data.intermediary
401
+ });
402
+ if (numResolved === quotePromises.length) {
403
+ clearTimeout(timeout);
404
+ resolve(quotes);
405
+ return;
406
+ }
407
+ }).catch(e => {
408
+ numResolved++;
409
+ if (e instanceof IntermediaryError_1.IntermediaryError) {
410
+ //Blacklist that node
411
+ this.intermediaryDiscovery.removeIntermediary(data.intermediary);
412
+ swapLimitsChanged = true;
413
+ }
414
+ else if (e instanceof RequestError_1.OutOfBoundsError) {
415
+ if (min == null || max == null) {
416
+ min = e.min;
417
+ max = e.max;
418
+ }
419
+ else {
420
+ min = (0, Utils_1.bigIntMin)(min, e.min);
421
+ max = (0, Utils_1.bigIntMax)(max, e.max);
422
+ }
423
+ data.intermediary.swapBounds[swapType] ??= {};
424
+ data.intermediary.swapBounds[swapType][chainIdentifier] ??= {};
425
+ const tokenBoundsData = (data.intermediary.swapBounds[swapType][chainIdentifier][amountData.token] ??= { input: {}, output: {} });
426
+ if (amountData.exactIn) {
427
+ tokenBoundsData.input = { min: e.min, max: e.max };
428
+ }
429
+ else {
430
+ tokenBoundsData.output = { min: e.min, max: e.max };
431
+ }
432
+ swapLimitsChanged = true;
433
+ }
434
+ this.logger.warn("createSwap(): Intermediary " + data.intermediary.url + " error: ", e);
435
+ error = e;
436
+ if (numResolved === quotePromises.length) {
437
+ if (timeout != null)
438
+ clearTimeout(timeout);
439
+ if (quotes.length > 0) {
440
+ resolve(quotes);
441
+ return;
442
+ }
443
+ if (min != null && max != null) {
444
+ let msg = "Swap amount too high or too low! Try swapping a different amount.";
445
+ if (amountData.amount != null) {
446
+ if (min > amountData.amount)
447
+ msg = "Swap amount too low! Try swapping a higher amount.";
448
+ if (max < amountData.amount)
449
+ msg = "Swap amount too high! Try swapping a lower amount.";
450
+ }
451
+ reject(new RequestError_1.OutOfBoundsError(msg, 400, min, max));
452
+ return;
453
+ }
454
+ reject(error);
455
+ }
456
+ });
457
+ });
458
+ });
459
+ try {
460
+ const quotes = await promiseAll;
461
+ //TODO: Intermediary's reputation is not taken into account!
462
+ quotes.sort((a, b) => {
463
+ if (amountData.exactIn) {
464
+ //Compare outputs
465
+ return (0, Utils_1.bigIntCompare)(b.quote.getOutput().rawAmount, a.quote.getOutput().rawAmount);
466
+ }
467
+ else {
468
+ //Compare inputs
469
+ return (0, Utils_1.bigIntCompare)(a.quote.getInput().rawAmount, b.quote.getInput().rawAmount);
470
+ }
471
+ });
472
+ this.logger.debug("createSwap(): Sorted quotes, best price to worst: ", quotes);
473
+ if (swapLimitsChanged)
474
+ this.emit("swapLimitsChanged");
475
+ const quote = quotes[0].quote;
476
+ await quote._save();
477
+ return quote;
478
+ }
479
+ catch (e) {
480
+ if (swapLimitsChanged)
481
+ this.emit("swapLimitsChanged");
482
+ throw e;
483
+ }
484
+ }
485
+ /**
486
+ * Creates Smart chain -> Bitcoin ({@link SwapType.TO_BTC}) swap
487
+ *
488
+ * @param chainIdentifier Chain identifier string of the source smart chain
489
+ * @param signer Signer's address on the source chain
490
+ * @param tokenAddress Token address to pay with
491
+ * @param address Recipient's bitcoin address
492
+ * @param amount Amount to send in token based units (if `exactIn=true`) or receive in satoshis (if `exactIn=false`)
493
+ * @param exactIn Whether to use exact in instead of exact out
494
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
495
+ * @param options Additional options for the swap
496
+ */
497
+ createToBTCSwap(chainIdentifier, signer, tokenAddress, address, amount, exactIn = false, additionalParams = this.options.defaultAdditionalParameters, options) {
498
+ if (this._chains[chainIdentifier] == null)
499
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
500
+ if (address.startsWith("bitcoin:")) {
501
+ address = address.substring(8).split("?")[0];
502
+ }
503
+ if (!this.Utils.isValidBitcoinAddress(address))
504
+ throw new Error("Invalid bitcoin address");
505
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(signer, true))
506
+ throw new Error("Invalid " + chainIdentifier + " address");
507
+ signer = this._chains[chainIdentifier].chainInterface.normalizeAddress(signer);
508
+ const amountData = {
509
+ amount,
510
+ token: tokenAddress,
511
+ exactIn
512
+ };
513
+ return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType_1.SwapType.TO_BTC].create(signer, address, amountData, candidates, options, additionalParams, abortSignal)), amountData, SwapType_1.SwapType.TO_BTC);
514
+ }
515
+ /**
516
+ * Creates Smart chain -> Bitcoin Lightning ({@link SwapType.TO_BTCLN}) swap
517
+ *
518
+ * @param chainIdentifier Chain identifier string of the source smart chain
519
+ * @param signer Signer's address on the source chain
520
+ * @param tokenAddress Token address to pay with
521
+ * @param paymentRequest BOLT11 lightning network invoice to be paid (needs to have a fixed amount), and the swap
522
+ * amount is taken from this fixed amount, hence only exact output swaps are supported
523
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
524
+ * @param options Additional options for the swap
525
+ */
526
+ async createToBTCLNSwap(chainIdentifier, signer, tokenAddress, paymentRequest, additionalParams = this.options.defaultAdditionalParameters, options) {
527
+ if (this._chains[chainIdentifier] == null)
528
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
529
+ if (paymentRequest.startsWith("lightning:"))
530
+ paymentRequest = paymentRequest.substring(10);
531
+ if (!this.Utils.isValidLightningInvoice(paymentRequest))
532
+ throw new Error("Invalid lightning network invoice");
533
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(signer, true))
534
+ throw new Error("Invalid " + chainIdentifier + " address");
535
+ signer = this._chains[chainIdentifier].chainInterface.normalizeAddress(signer);
536
+ const parsedPR = (0, bolt11_1.decode)(paymentRequest);
537
+ if (parsedPR.millisatoshis == null)
538
+ throw new Error("Invalid lightning network invoice, no msat value field!");
539
+ const amountData = {
540
+ amount: (BigInt(parsedPR.millisatoshis) + 999n) / 1000n,
541
+ token: tokenAddress,
542
+ exactIn: false
543
+ };
544
+ return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => chain.wrappers[SwapType_1.SwapType.TO_BTCLN].create(signer, paymentRequest, amountData, candidates, options, additionalParams, abortSignal), amountData, SwapType_1.SwapType.TO_BTCLN);
545
+ }
546
+ /**
547
+ * Creates Smart chain -> Bitcoin Lightning ({@link SwapType.TO_BTCLN}) swap via LNURL-pay link
548
+ *
549
+ * @param chainIdentifier Chain identifier string of the source smart chain
550
+ * @param signer Signer's address on the source chain
551
+ * @param tokenAddress Token address to pay with
552
+ * @param lnurlPay LNURL-pay link to use for the payment
553
+ * @param amount Amount to send in token based units (if `exactIn=true`) or receive in satoshis (if `exactIn=false`)
554
+ * @param exactIn Whether to do an exact in swap instead of exact out
555
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
556
+ * @param options Additional options for the swap
557
+ */
558
+ async createToBTCLNSwapViaLNURL(chainIdentifier, signer, tokenAddress, lnurlPay, amount, exactIn = false, additionalParams = this.options.defaultAdditionalParameters, options) {
559
+ if (this._chains[chainIdentifier] == null)
560
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
561
+ if (typeof (lnurlPay) === "string" && !this.Utils.isValidLNURL(lnurlPay))
562
+ throw new Error("Invalid LNURL-pay link");
563
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(signer, true))
564
+ throw new Error("Invalid " + chainIdentifier + " address");
565
+ signer = this._chains[chainIdentifier].chainInterface.normalizeAddress(signer);
566
+ const amountData = {
567
+ amount,
568
+ token: tokenAddress,
569
+ exactIn
570
+ };
571
+ return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => chain.wrappers[SwapType_1.SwapType.TO_BTCLN].createViaLNURL(signer, typeof (lnurlPay) === "string" ? (lnurlPay.startsWith("lightning:") ? lnurlPay.substring(10) : lnurlPay) : lnurlPay.params, amountData, candidates, options, additionalParams, abortSignal), amountData, SwapType_1.SwapType.TO_BTCLN);
572
+ }
573
+ /**
574
+ * Creates Smart chain -> Bitcoin Lightning ({@link SwapType.TO_BTCLN}) swap via {@link LightningInvoiceCreateService}
575
+ *
576
+ * @param chainIdentifier Chain identifier string of the source smart chain
577
+ * @param signer Signer's address on the source chain
578
+ * @param tokenAddress Token address to pay with
579
+ * @param service Invoice create service object which facilitates the creation of fixed amount LN invoices
580
+ * @param amount Amount to send in token based units (if `exactIn=true`) or receive in satoshis (if `exactIn=false`)
581
+ * @param exactIn Whether to do an exact in swap instead of exact out
582
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
583
+ * @param options Additional options for the swap
584
+ */
585
+ async createToBTCLNSwapViaInvoiceCreateService(chainIdentifier, signer, tokenAddress, service, amount, exactIn = false, additionalParams = this.options.defaultAdditionalParameters, options) {
586
+ if (this._chains[chainIdentifier] == null)
587
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
588
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(signer, true))
589
+ throw new Error("Invalid " + chainIdentifier + " address");
590
+ signer = this._chains[chainIdentifier].chainInterface.normalizeAddress(signer);
591
+ const amountData = {
592
+ amount,
593
+ token: tokenAddress,
594
+ exactIn
595
+ };
596
+ return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => chain.wrappers[SwapType_1.SwapType.TO_BTCLN].createViaInvoiceCreateService(signer, Promise.resolve(service), amountData, candidates, options, additionalParams, abortSignal), amountData, SwapType_1.SwapType.TO_BTCLN);
597
+ }
598
+ /**
599
+ * Creates Bitcoin -> Smart chain ({@link SwapType.SPV_VAULT_FROM_BTC}) swap
600
+ *
601
+ * @param chainIdentifier Chain identifier string of the destination smart chain
602
+ * @param recipient Recipient address on the destination chain
603
+ * @param tokenAddress Token address to receive
604
+ * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
605
+ * @param exactOut Whether to use a exact out instead of exact in
606
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
607
+ * @param options Additional options for the swap
608
+ */
609
+ async createFromBTCSwapNew(chainIdentifier, recipient, tokenAddress, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
610
+ if (this._chains[chainIdentifier] == null)
611
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
612
+ if (this._chains[chainIdentifier].wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC] == null)
613
+ throw new Error("Chain " + chainIdentifier + " doesn't support new BTC swap protocol (spv vault swaps)!");
614
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
615
+ throw new Error("Invalid " + chainIdentifier + " address");
616
+ recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
617
+ const amountData = {
618
+ amount: amount ?? undefined,
619
+ token: tokenAddress,
620
+ exactIn: !exactOut
621
+ };
622
+ return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC].create(recipient, amountData, candidates, options, additionalParams, abortSignal)), amountData, SwapType_1.SwapType.SPV_VAULT_FROM_BTC);
623
+ }
624
+ /**
625
+ * Creates LEGACY Bitcoin -> Smart chain ({@link SwapType.FROM_BTC}) swap
626
+ *
627
+ * @param chainIdentifier Chain identifier string of the destination smart chain
628
+ * @param recipient Recipient address on the destination chain
629
+ * @param tokenAddress Token address to receive
630
+ * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
631
+ * @param exactOut Whether to use a exact out instead of exact in
632
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
633
+ * @param options Additional options for the swap
634
+ */
635
+ async createFromBTCSwap(chainIdentifier, recipient, tokenAddress, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
636
+ if (this._chains[chainIdentifier] == null)
637
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
638
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
639
+ throw new Error("Invalid " + chainIdentifier + " address");
640
+ recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
641
+ const amountData = {
642
+ amount,
643
+ token: tokenAddress,
644
+ exactIn: !exactOut
645
+ };
646
+ return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType_1.SwapType.FROM_BTC].create(recipient, amountData, candidates, options, additionalParams, abortSignal)), amountData, SwapType_1.SwapType.FROM_BTC);
647
+ }
648
+ /**
649
+ * Creates LEGACY Bitcoin Lightning -> Smart chain ({@link SwapType.FROM_BTCLN}) swap
650
+ *
651
+ * @param chainIdentifier Chain identifier string of the destination smart chain
652
+ * @param recipient Recipient address on the destination chain
653
+ * @param tokenAddress Token address to receive
654
+ * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
655
+ * @param exactOut Whether to use a exact out instead of exact in
656
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
657
+ * @param options Additional options for the swap
658
+ */
659
+ async createFromBTCLNSwap(chainIdentifier, recipient, tokenAddress, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
660
+ if (this._chains[chainIdentifier] == null)
661
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
662
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
663
+ throw new Error("Invalid " + chainIdentifier + " address");
664
+ recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
665
+ const amountData = {
666
+ amount,
667
+ token: tokenAddress,
668
+ exactIn: !exactOut
669
+ };
670
+ return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType_1.SwapType.FROM_BTCLN].create(recipient, amountData, candidates, options, additionalParams, abortSignal)), amountData, SwapType_1.SwapType.FROM_BTCLN);
671
+ }
672
+ /**
673
+ * Creates LEGACY Bitcoin Lightning -> Smart chain ({@link SwapType.FROM_BTCLN}) swap, withdrawing from
674
+ * an LNURL-withdraw link
675
+ *
676
+ * @param chainIdentifier Chain identifier string of the destination smart chain
677
+ * @param recipient Recipient address on the destination chain
678
+ * @param tokenAddress Token address to receive
679
+ * @param lnurl LNURL-withdraw link to pull the funds from
680
+ * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
681
+ * @param exactOut Whether to use a exact out instead of exact in
682
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
683
+ * @param options Additional options for the swap
684
+ */
685
+ async createFromBTCLNSwapViaLNURL(chainIdentifier, recipient, tokenAddress, lnurl, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
686
+ if (this._chains[chainIdentifier] == null)
687
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
688
+ if (typeof (lnurl) === "string" && !this.Utils.isValidLNURL(lnurl))
689
+ throw new Error("Invalid LNURL-withdraw link");
690
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
691
+ throw new Error("Invalid " + chainIdentifier + " address");
692
+ recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
693
+ const amountData = {
694
+ amount,
695
+ token: tokenAddress,
696
+ exactIn: !exactOut
697
+ };
698
+ return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => chain.wrappers[SwapType_1.SwapType.FROM_BTCLN].createViaLNURL(recipient, typeof (lnurl) === "string" ? (lnurl.startsWith("lightning:") ? lnurl.substring(10) : lnurl) : lnurl.params, amountData, candidates, options, additionalParams, abortSignal), amountData, SwapType_1.SwapType.FROM_BTCLN);
699
+ }
700
+ /**
701
+ * Creates Bitcoin Lightning -> Smart chain ({@link SwapType.FROM_BTCLN_AUTO}) swap
702
+ *
703
+ * @param chainIdentifier Chain identifier string of the destination smart chain
704
+ * @param recipient Recipient address on the destination chain
705
+ * @param tokenAddress Token address to receive
706
+ * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
707
+ * @param exactOut Whether to use a exact out instead of exact in
708
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
709
+ * @param options Additional options for the swap
710
+ */
711
+ async createFromBTCLNSwapNew(chainIdentifier, recipient, tokenAddress, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
712
+ if (this._chains[chainIdentifier] == null)
713
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
714
+ if (this._chains[chainIdentifier].wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] == null)
715
+ throw new Error("Chain " + chainIdentifier + " doesn't support new lightning swap protocol (from btcln auto)!");
716
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
717
+ throw new Error("Invalid " + chainIdentifier + " address");
718
+ recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
719
+ const amountData = {
720
+ amount,
721
+ token: tokenAddress,
722
+ exactIn: !exactOut
723
+ };
724
+ return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO].create(recipient, amountData, candidates, options, additionalParams, abortSignal)), amountData, SwapType_1.SwapType.FROM_BTCLN_AUTO);
725
+ }
726
+ /**
727
+ * Creates Bitcoin Lightning -> Smart chain ({@link SwapType.FROM_BTCLN_AUTO}) swap, withdrawing from
728
+ * an LNURL-withdraw link
729
+ *
730
+ * @param chainIdentifier Chain identifier string of the destination smart chain
731
+ * @param recipient Recipient address on the destination chain
732
+ * @param tokenAddress Token address to receive
733
+ * @param lnurl LNURL-withdraw link to pull the funds from
734
+ * @param amount Amount to send in satoshis (if `exactOut=false`) or receive in token based units (if `exactOut=true`)
735
+ * @param exactOut Whether to use a exact out instead of exact in
736
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
737
+ * @param options Additional options for the swap
738
+ */
739
+ async createFromBTCLNSwapNewViaLNURL(chainIdentifier, recipient, tokenAddress, lnurl, amount, exactOut = false, additionalParams = this.options.defaultAdditionalParameters, options) {
740
+ if (this._chains[chainIdentifier] == null)
741
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
742
+ if (this._chains[chainIdentifier].wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] == null)
743
+ throw new Error("Chain " + chainIdentifier + " doesn't support new lightning swap protocol (from btcln auto)!");
744
+ if (typeof (lnurl) === "string" && !this.Utils.isValidLNURL(lnurl))
745
+ throw new Error("Invalid LNURL-withdraw link");
746
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
747
+ throw new Error("Invalid " + chainIdentifier + " address");
748
+ recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
749
+ const amountData = {
750
+ amount,
751
+ token: tokenAddress,
752
+ exactIn: !exactOut
753
+ };
754
+ return this.createSwap(chainIdentifier, (candidates, abortSignal, chain) => chain.wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO].createViaLNURL(recipient, typeof (lnurl) === "string" ? (lnurl.startsWith("lightning:") ? lnurl.substring(10) : lnurl) : lnurl.params, amountData, candidates, options, additionalParams, abortSignal), amountData, SwapType_1.SwapType.FROM_BTCLN_AUTO);
755
+ }
756
+ /**
757
+ * Creates a trusted Bitcoin Lightning -> Smart chain ({@link SwapType.TRUSTED_FROM_BTCLN}) gas swap
758
+ *
759
+ * @param chainIdentifier Chain identifier string of the destination smart chain
760
+ * @param recipient Recipient address on the destination chain
761
+ * @param amount Amount of native token to receive, in base units
762
+ * @param trustedIntermediaryOrUrl URL or Intermediary object of the trusted intermediary to use, otherwise uses default
763
+ * @throws {Error} If no trusted intermediary specified
764
+ */
765
+ async createTrustedLNForGasSwap(chainIdentifier, recipient, amount, trustedIntermediaryOrUrl) {
766
+ if (this._chains[chainIdentifier] == null)
767
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
768
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
769
+ throw new Error("Invalid " + chainIdentifier + " address");
770
+ recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
771
+ const useUrl = trustedIntermediaryOrUrl ?? this.defaultTrustedIntermediary ?? this.options.defaultTrustedIntermediaryUrl;
772
+ if (useUrl == null)
773
+ throw new Error("No trusted intermediary specified!");
774
+ const swap = await this._chains[chainIdentifier].wrappers[SwapType_1.SwapType.TRUSTED_FROM_BTCLN].create(recipient, amount, useUrl);
775
+ await swap._save();
776
+ return swap;
777
+ }
778
+ /**
779
+ * Creates a trusted Bitcoin -> Smart chain ({@link SwapType.TRUSTED_FROM_BTC}) gas swap
780
+ *
781
+ * @param chainIdentifier Chain identifier string of the destination smart chain
782
+ * @param recipient Recipient address on the destination chain
783
+ * @param amount Amount of native token to receive, in base units
784
+ * @param refundAddress Bitcoin refund address, in case the swap fails the funds are refunded here
785
+ * @param trustedIntermediaryOrUrl URL or Intermediary object of the trusted intermediary to use, otherwise uses default
786
+ * @throws {Error} If no trusted intermediary specified
787
+ */
788
+ async createTrustedOnchainForGasSwap(chainIdentifier, recipient, amount, refundAddress, trustedIntermediaryOrUrl) {
789
+ if (this._chains[chainIdentifier] == null)
790
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
791
+ if (!this._chains[chainIdentifier].chainInterface.isValidAddress(recipient, true))
792
+ throw new Error("Invalid " + chainIdentifier + " address");
793
+ recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
794
+ const useUrl = trustedIntermediaryOrUrl ?? this.defaultTrustedIntermediary ?? this.options.defaultTrustedIntermediaryUrl;
795
+ if (useUrl == null)
796
+ throw new Error("No trusted intermediary specified!");
797
+ const swap = await this._chains[chainIdentifier].wrappers[SwapType_1.SwapType.TRUSTED_FROM_BTC].create(recipient, amount, useUrl, refundAddress);
798
+ await swap._save();
799
+ return swap;
800
+ }
801
+ /**
802
+ * Creates a swap from srcToken to dstToken, of a specific token amount, either specifying input amount (exactIn=true)
803
+ * or output amount (exactIn=false), NOTE: For regular -> BTC-LN (lightning) swaps the passed amount is ignored and
804
+ * invoice's pre-set amount is used instead.
805
+ * @deprecated Use {@link swap} instead
806
+ *
807
+ * @param signer Smartchain (Solana, Starknet, etc.) address of the user
808
+ * @param srcToken Source token of the swap, user pays this token
809
+ * @param dstToken Destination token of the swap, user receives this token
810
+ * @param amount Amount of the swap
811
+ * @param exactIn Whether the amount specified is an input amount (exactIn=true) or an output amount (exactIn=false)
812
+ * @param addressLnurlLightningInvoice Bitcoin on-chain address, lightning invoice, LNURL-pay to pay or
813
+ * LNURL-withdrawal to withdraw money from
814
+ */
815
+ create(signer, srcToken, dstToken, amount, exactIn, addressLnurlLightningInvoice) {
816
+ if (srcToken.chain === "BTC") {
817
+ return this.swap(srcToken, dstToken, amount, exactIn, addressLnurlLightningInvoice, signer);
818
+ }
819
+ else {
820
+ return this.swap(srcToken, dstToken, amount, exactIn, signer, addressLnurlLightningInvoice);
821
+ }
822
+ }
823
+ /**
824
+ * Creates a swap from srcToken to dstToken, of a specific token amount, either specifying input amount (if `exactIn=true`)
825
+ * or output amount (if `exactIn=false`), NOTE: For regular Smart chain -> BTC-LN (lightning) swaps the passed amount is ignored and
826
+ * invoice's pre-set amount is used instead, use LNURL-pay links for dynamic amounts
827
+ *
828
+ * @param _srcToken Source token of the swap, user pays this token
829
+ * @param _dstToken Destination token of the swap, user receives this token
830
+ * @param _amount Amount of the swap either in base units as {bigint} or in human readable format (with decimals) as {string}
831
+ * @param exactIn Whether the amount specified is an input amount (exactIn=true) or an output amount (exactIn=false)
832
+ * @param src Source wallet/lnurl-withdraw of the swap
833
+ * @param dst Destination smart chain address, bitcoin on-chain address, lightning invoice, LNURL-pay
834
+ * @param options Options for the swap
835
+ */
836
+ swap(_srcToken, _dstToken, _amount, exactIn, src, dst, options) {
837
+ const srcToken = typeof (_srcToken) === "string" ? this.getToken(_srcToken) : _srcToken;
838
+ const dstToken = typeof (_dstToken) === "string" ? this.getToken(_dstToken) : _dstToken;
839
+ const amount = _amount == null ? null : (typeof (_amount) === "bigint" ? _amount : (0, Utils_1.fromDecimal)(_amount, exactIn ? srcToken.decimals : dstToken.decimals));
840
+ if ((0, Token_1.isBtcToken)(srcToken)) {
841
+ if ((0, Token_1.isSCToken)(dstToken)) {
842
+ if (typeof (dst) !== "string")
843
+ throw new Error("Destination for BTC/BTC-LN -> smart chain swaps must be a smart chain address!");
844
+ if (amount == null)
845
+ throw new Error("Amount cannot be null for from btc swaps!");
846
+ if (srcToken.lightning) {
847
+ //FROM_BTCLN
848
+ if (src != null) {
849
+ if (typeof (src) !== "string" && !(0, LNURLWithdraw_1.isLNURLWithdraw)(src))
850
+ throw new Error("LNURL must be a string or LNURLWithdraw object!");
851
+ return this.supportsSwapType(dstToken.chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO) ?
852
+ this.createFromBTCLNSwapNewViaLNURL(dstToken.chainId, dst, dstToken.address, src, amount, !exactIn, undefined, options) :
853
+ this.createFromBTCLNSwapViaLNURL(dstToken.chainId, dst, dstToken.address, src, amount, !exactIn, undefined, options);
854
+ }
855
+ else {
856
+ return this.supportsSwapType(dstToken.chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO) ?
857
+ this.createFromBTCLNSwapNew(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options) :
858
+ this.createFromBTCLNSwap(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options);
859
+ }
860
+ }
861
+ else {
862
+ //FROM_BTC
863
+ if (this.supportsSwapType(dstToken.chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC)) {
864
+ return this.createFromBTCSwapNew(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options);
865
+ }
866
+ else {
867
+ return this.createFromBTCSwap(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options);
868
+ }
869
+ }
870
+ }
871
+ }
872
+ else if ((0, Token_1.isSCToken)(srcToken)) {
873
+ if ((0, Token_1.isBtcToken)(dstToken)) {
874
+ if (typeof (src) !== "string")
875
+ throw new Error("Source address for BTC/BTC-LN -> smart chain swaps must be a smart chain address!");
876
+ if (dstToken.lightning) {
877
+ //TO_BTCLN
878
+ if (typeof (dst) !== "string" && !(0, LNURLPay_1.isLNURLPay)(dst))
879
+ throw new Error("Destination LNURL link/lightning invoice must be a string or LNURLPay object!");
880
+ if ((0, LNURLPay_1.isLNURLPay)(dst) || this.Utils.isValidLNURL(dst)) {
881
+ if (amount == null)
882
+ throw new Error("Amount cannot be null for to btcln swaps via LNURL-pay!");
883
+ return this.createToBTCLNSwapViaLNURL(srcToken.chainId, src, srcToken.address, dst, amount, !!exactIn, undefined, options);
884
+ }
885
+ else if ((0, LightningInvoiceCreateService_1.isLightningInvoiceCreateService)(dst)) {
886
+ if (amount == null)
887
+ throw new Error("Amount cannot be null for to btcln swaps via InvoiceCreateService!");
888
+ return this.createToBTCLNSwapViaInvoiceCreateService(srcToken.chainId, src, srcToken.address, dst, amount, !!exactIn, undefined, options);
889
+ }
890
+ else if (this.Utils.isLightningInvoice(dst)) {
891
+ if (!this.Utils.isValidLightningInvoice(dst))
892
+ throw new Error("Invalid lightning invoice specified, lightning invoice MUST contain pre-set amount!");
893
+ if (exactIn)
894
+ throw new Error("Only exact out swaps are possible with lightning invoices, use LNURL links for exact in lightning swaps!");
895
+ return this.createToBTCLNSwap(srcToken.chainId, src, srcToken.address, dst, undefined, options);
896
+ }
897
+ else {
898
+ throw new Error("Supplied parameter is not LNURL link nor lightning invoice (bolt11)!");
899
+ }
900
+ }
901
+ else {
902
+ //TO_BTC
903
+ if (typeof (dst) !== "string")
904
+ throw new Error("Destination bitcoin address must be a string!");
905
+ if (amount == null)
906
+ throw new Error("Amount cannot be null for to btc swaps!");
907
+ return this.createToBTCSwap(srcToken.chainId, src, srcToken.address, dst, amount, !!exactIn, undefined, options);
908
+ }
909
+ }
910
+ }
911
+ throw new Error("Unsupported swap type");
912
+ }
913
+ /**
914
+ * A helper function to sweep all the funds from a given wallet in a single swap, after getting the quote you can
915
+ * execute the swap by passing the returned `feeRate` and `utxos` to the {@link SpvFromBTCSwap.execute},
916
+ * {@link SpvFromBTCSwap.getFundedPsbt} or {@link SpvFromBTCSwap.sendBitcoinTransaction} functions along
917
+ * with `spendFully=true`.
918
+ *
919
+ * @example
920
+ * Create the swap first using this function
921
+ * ```ts
922
+ * const {swap, utxos, btcFeeRate} = await swapper.sweepBitcoinWallet(wallet, Tokens.CITREA.CBTC, dstAddress);
923
+ * ```
924
+ * Then execute it using one of these execution paths - ensure that you supply the returned `utxos`, `btcFeeRate`
925
+ * params and also set `spendFully` to `true`!
926
+ *
927
+ * a) Execute and pass the returned utxos and btcFeeRate:
928
+ * ```ts
929
+ * await swap.execute(wallet, undefined, {feeRate: btcFeeRate, utxos: utxos, spendFully: true});
930
+ * ```
931
+ *
932
+ * b) Get funded PSBT to sign externally:
933
+ * ```ts
934
+ * const {psbt, psbtHex, psbtBase64, signInputs} = await swap.getFundedPsbt(wallet, btcFeeRate, undefined, utxos, true);
935
+ * // Sign the psbt at the specified signInputs indices
936
+ * const signedPsbt = ...;
937
+ * // Then submit back to the SDK
938
+ * await swap.submitPsbt(signedPsbt);
939
+ * ```
940
+ *
941
+ * c) Only sign and send the signed PSBT with the provided wallet:
942
+ * ```ts
943
+ * await swap.sendBitcoinTransaction(wallet, btcFeeRate, utxos, true);
944
+ * ```
945
+ */
946
+ async sweepBitcoinWallet(srcWallet, _dstToken, dstAddress, options) {
947
+ const dstToken = typeof (_dstToken) === "string" ? this.getToken(_dstToken) : _dstToken;
948
+ if (!(0, Token_1.isSCToken)(dstToken))
949
+ throw new Error("Destination token must be a smart chain token!");
950
+ const wallet = (0, BitcoinWalletUtils_1.toBitcoinWallet)(srcWallet, this._bitcoinRpc, this.bitcoinNetwork);
951
+ if (wallet.getUtxoPool == null)
952
+ throw new Error("Wallet needs to support the `getUtxoPool()` function!");
953
+ const walletUtxosPromise = wallet.getUtxoPool();
954
+ const bitcoinFeeRatePromise = options?.bitcoinFeeRate ?? wallet.getFeeRate();
955
+ const swap = await this.createFromBTCSwapNew(dstToken.chainId, dstAddress, dstToken.address, null, false, undefined, {
956
+ ...options,
957
+ sourceWalletUtxos: walletUtxosPromise,
958
+ bitcoinFeeRate: bitcoinFeeRatePromise
959
+ });
960
+ return {
961
+ swap,
962
+ utxos: await walletUtxosPromise,
963
+ btcFeeRate: Math.max(swap.minimumBtcFeeRate, await bitcoinFeeRatePromise)
964
+ };
965
+ }
966
+ async getAllSwaps(chainId, signer) {
967
+ const queryParams = [];
968
+ if (signer != null)
969
+ queryParams.push({ key: "initiator", value: signer });
970
+ if (chainId == null) {
971
+ const res = await Promise.all(Object.keys(this._chains).map((chainId) => {
972
+ const { unifiedSwapStorage, reviver } = this._chains[chainId];
973
+ return unifiedSwapStorage.query([queryParams], reviver);
974
+ }));
975
+ return res.flat();
976
+ }
977
+ else {
978
+ const { unifiedSwapStorage, reviver } = this._chains[chainId];
979
+ return await unifiedSwapStorage.query([queryParams], reviver);
980
+ }
981
+ }
982
+ async getActionableSwaps(chainId, signer) {
983
+ if (chainId == null) {
984
+ const res = await Promise.all(Object.keys(this._chains).map((chainId) => {
985
+ const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
986
+ const queryParams = [];
987
+ for (let key in wrappers) {
988
+ const wrapper = wrappers[key];
989
+ const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
990
+ if (signer != null)
991
+ swapTypeQueryParams.push({ key: "initiator", value: signer });
992
+ swapTypeQueryParams.push({ key: "state", value: wrapper._pendingSwapStates });
993
+ queryParams.push(swapTypeQueryParams);
994
+ }
995
+ return unifiedSwapStorage.query(queryParams, reviver);
996
+ }));
997
+ return res.flat().filter(swap => swap.requiresAction());
998
+ }
999
+ else {
1000
+ const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1001
+ const queryParams = [];
1002
+ for (let key in wrappers) {
1003
+ const wrapper = wrappers[key];
1004
+ const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1005
+ if (signer != null)
1006
+ swapTypeQueryParams.push({ key: "initiator", value: signer });
1007
+ swapTypeQueryParams.push({ key: "state", value: wrapper._pendingSwapStates });
1008
+ queryParams.push(swapTypeQueryParams);
1009
+ }
1010
+ return (await unifiedSwapStorage.query(queryParams, reviver)).filter(swap => swap.requiresAction());
1011
+ }
1012
+ }
1013
+ async getRefundableSwaps(chainId, signer) {
1014
+ if (chainId == null) {
1015
+ const res = await Promise.all(Object.keys(this._chains).map((chainId) => {
1016
+ const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1017
+ const queryParams = [];
1018
+ for (let wrapper of [wrappers[SwapType_1.SwapType.TO_BTCLN], wrappers[SwapType_1.SwapType.TO_BTC]]) {
1019
+ const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1020
+ if (signer != null)
1021
+ swapTypeQueryParams.push({ key: "initiator", value: signer });
1022
+ swapTypeQueryParams.push({ key: "state", value: wrapper._refundableSwapStates });
1023
+ queryParams.push(swapTypeQueryParams);
1024
+ }
1025
+ return unifiedSwapStorage.query(queryParams, reviver);
1026
+ }));
1027
+ return res.flat().filter(swap => swap.isRefundable());
1028
+ }
1029
+ else {
1030
+ const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1031
+ const queryParams = [];
1032
+ for (let wrapper of [wrappers[SwapType_1.SwapType.TO_BTCLN], wrappers[SwapType_1.SwapType.TO_BTC]]) {
1033
+ const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1034
+ if (signer != null)
1035
+ swapTypeQueryParams.push({ key: "initiator", value: signer });
1036
+ swapTypeQueryParams.push({ key: "state", value: wrapper._refundableSwapStates });
1037
+ queryParams.push(swapTypeQueryParams);
1038
+ }
1039
+ const result = await unifiedSwapStorage.query(queryParams, reviver);
1040
+ return result.filter(swap => swap.isRefundable());
1041
+ }
1042
+ }
1043
+ async getClaimableSwaps(chainId, signer) {
1044
+ if (chainId == null) {
1045
+ const res = await Promise.all(Object.keys(this._chains).map((chainId) => {
1046
+ const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1047
+ const queryParams = [];
1048
+ for (let wrapper of [wrappers[SwapType_1.SwapType.FROM_BTC], wrappers[SwapType_1.SwapType.FROM_BTCLN], wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC], wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO]]) {
1049
+ if (wrapper == null)
1050
+ continue;
1051
+ const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1052
+ if (signer != null)
1053
+ swapTypeQueryParams.push({ key: "initiator", value: signer });
1054
+ swapTypeQueryParams.push({ key: "state", value: wrapper._claimableSwapStates });
1055
+ queryParams.push(swapTypeQueryParams);
1056
+ }
1057
+ return unifiedSwapStorage.query(queryParams, reviver);
1058
+ }));
1059
+ return res.flat().filter(swap => swap.isClaimable());
1060
+ }
1061
+ else {
1062
+ const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1063
+ const queryParams = [];
1064
+ for (let wrapper of [wrappers[SwapType_1.SwapType.FROM_BTC], wrappers[SwapType_1.SwapType.FROM_BTCLN], wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC], wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO]]) {
1065
+ if (wrapper == null)
1066
+ continue;
1067
+ const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1068
+ if (signer != null)
1069
+ swapTypeQueryParams.push({ key: "initiator", value: signer });
1070
+ swapTypeQueryParams.push({ key: "state", value: wrapper._claimableSwapStates });
1071
+ queryParams.push(swapTypeQueryParams);
1072
+ }
1073
+ const result = await unifiedSwapStorage.query(queryParams, reviver);
1074
+ return result.filter(swap => swap.isClaimable());
1075
+ }
1076
+ }
1077
+ async getSwapById(id, chainId, signer) {
1078
+ //Check in pending swaps first
1079
+ if (chainId != null) {
1080
+ for (let key in this._chains[chainId].wrappers) {
1081
+ const wrapper = this._chains[chainId].wrappers[key];
1082
+ const result = wrapper._getPendingSwap(id);
1083
+ if (result != null) {
1084
+ if (signer != null) {
1085
+ if (result._getInitiator() === signer)
1086
+ return result;
1087
+ }
1088
+ else {
1089
+ return result;
1090
+ }
1091
+ }
1092
+ }
1093
+ }
1094
+ else {
1095
+ for (let chainId in this._chains) {
1096
+ for (let key in this._chains[chainId].wrappers) {
1097
+ const wrapper = this._chains[chainId].wrappers[key];
1098
+ const result = wrapper._getPendingSwap(id);
1099
+ if (result != null) {
1100
+ if (signer != null) {
1101
+ if (result._getInitiator() === signer)
1102
+ return result;
1103
+ }
1104
+ else {
1105
+ return result;
1106
+ }
1107
+ }
1108
+ }
1109
+ }
1110
+ }
1111
+ const queryParams = [];
1112
+ if (signer != null)
1113
+ queryParams.push({ key: "initiator", value: signer });
1114
+ queryParams.push({ key: "id", value: id });
1115
+ if (chainId == null) {
1116
+ const res = await Promise.all(Object.keys(this._chains).map((chainId) => {
1117
+ const { unifiedSwapStorage, reviver } = this._chains[chainId];
1118
+ return unifiedSwapStorage.query([queryParams], reviver);
1119
+ }));
1120
+ return res.flat()[0];
1121
+ }
1122
+ else {
1123
+ const { unifiedSwapStorage, reviver } = this._chains[chainId];
1124
+ return (await unifiedSwapStorage.query([queryParams], reviver))[0];
1125
+ }
1126
+ }
1127
+ /**
1128
+ * Returns the swap with a proper return type, or `undefined` if not found or has wrong type
1129
+ *
1130
+ * @param id An ID of the swap ({@link ISwap.getId})
1131
+ * @param chainId Chain identifier of the smart chain where the swap was initiated
1132
+ * @param swapType Type of the swap
1133
+ * @param signer An optional required smart chain signer address to fetch the swap for
1134
+ */
1135
+ async getTypedSwapById(id, chainId, swapType, signer) {
1136
+ let _swapType = swapType;
1137
+ if (swapType === SwapType_1.SwapType.FROM_BTC && this.supportsSwapType(chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC))
1138
+ _swapType = SwapType_1.SwapType.SPV_VAULT_FROM_BTC;
1139
+ if (swapType === SwapType_1.SwapType.FROM_BTCLN && this.supportsSwapType(chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO))
1140
+ _swapType = SwapType_1.SwapType.FROM_BTCLN_AUTO;
1141
+ const wrapper = this._chains[chainId].wrappers[_swapType];
1142
+ if (wrapper == null)
1143
+ return;
1144
+ const result = wrapper._getPendingSwap(id);
1145
+ if (result != null) {
1146
+ if (signer != null) {
1147
+ if (result._getInitiator() === signer)
1148
+ return result;
1149
+ }
1150
+ else {
1151
+ return result;
1152
+ }
1153
+ }
1154
+ const queryParams = [];
1155
+ if (signer != null)
1156
+ queryParams.push({ key: "initiator", value: signer });
1157
+ queryParams.push({ key: "id", value: id });
1158
+ const { unifiedSwapStorage, reviver } = this._chains[chainId];
1159
+ const swap = (await unifiedSwapStorage.query([queryParams], reviver))[0];
1160
+ if ((0, SwapUtils_1.isSwapType)(swap, swapType))
1161
+ return swap;
1162
+ }
1163
+ async syncSwapsForChain(chainId, signer) {
1164
+ const { unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1165
+ const queryParams = [];
1166
+ for (let key in wrappers) {
1167
+ const wrapper = wrappers[key];
1168
+ const swapTypeQueryParams = [{ key: "type", value: wrapper.TYPE }];
1169
+ if (signer != null)
1170
+ swapTypeQueryParams.push({ key: "initiator", value: signer });
1171
+ swapTypeQueryParams.push({ key: "state", value: wrapper._pendingSwapStates });
1172
+ queryParams.push(swapTypeQueryParams);
1173
+ }
1174
+ this.logger.debug("_syncSwaps(): Querying swaps swaps for chain " + chainId + "!");
1175
+ const swaps = await unifiedSwapStorage.query(queryParams, reviver);
1176
+ this.logger.debug("_syncSwaps(): Syncing " + swaps.length + " swaps!");
1177
+ const changedSwaps = [];
1178
+ const removeSwaps = [];
1179
+ const assortedSwaps = {};
1180
+ swaps.forEach(swap => {
1181
+ (assortedSwaps[swap.getType()] ??= []).push(swap);
1182
+ });
1183
+ for (let key in assortedSwaps) {
1184
+ const swapType = key;
1185
+ const wrapperSwaps = assortedSwaps[swapType];
1186
+ const wrapper = wrappers[swapType];
1187
+ const result = await wrapper.checkPastSwaps(wrapperSwaps, true);
1188
+ changedSwaps.push(...result.changedSwaps);
1189
+ removeSwaps.push(...result.removeSwaps);
1190
+ }
1191
+ this.logger.debug("_syncSwaps(): Done syncing " + swaps.length + " swaps, saving " + changedSwaps.length + " changed swaps, removing " + removeSwaps.length + " swaps!");
1192
+ await unifiedSwapStorage.saveAll(changedSwaps);
1193
+ await unifiedSwapStorage.removeAll(removeSwaps);
1194
+ changedSwaps.forEach(swap => swap._emitEvent());
1195
+ removeSwaps.forEach(swap => swap._emitEvent());
1196
+ }
1197
+ /**
1198
+ * Deletes the swaps from the persistent storage backend. Note that some data (like lightning network
1199
+ * amounts and bolt11 invoices) are purely off-chain and can never be recovered later just from
1200
+ * on-chain data!
1201
+ *
1202
+ * @param chainId Optional, to only delete swaps for this smart chain
1203
+ * @param signer Optional, to only delete swaps for this smart chain signer (`chainId` param must be
1204
+ * set to delete only signer's swaps)
1205
+ */
1206
+ async wipeStorage(chainId, signer) {
1207
+ if (chainId == null) {
1208
+ const swaps = await this.getAllSwaps();
1209
+ const chainSwaps = {};
1210
+ swaps.forEach(swap => (chainSwaps[swap.chainIdentifier] ??= []).push(swap));
1211
+ for (let chainId in chainSwaps) {
1212
+ const currentChainSwaps = chainSwaps[chainId];
1213
+ if (this._chains[chainId] == null) {
1214
+ this.logger.warn(`wipeStorage(): Attempted to remove ${currentChainSwaps.length} swaps on ${chainId}, but smart chain not known!`);
1215
+ continue;
1216
+ }
1217
+ await this._chains[chainId].unifiedSwapStorage.removeAll(currentChainSwaps);
1218
+ this.logger.debug(`wipeStorage(): Successfully removed ${currentChainSwaps.length} swaps on ${chainId}!`);
1219
+ }
1220
+ }
1221
+ else {
1222
+ if (this._chains[chainId] == null)
1223
+ throw new Error(`wipeStorage(): Smart chain with identifier ${chainId} not found!`);
1224
+ const swaps = await this.getAllSwaps(chainId, signer);
1225
+ await this._chains[chainId].unifiedSwapStorage.removeAll(swaps);
1226
+ this.logger.debug(`wipeStorage(): Successfully removed ${swaps.length} swaps on ${chainId}!`);
1227
+ }
1228
+ }
1229
+ /**
1230
+ * Synchronizes swaps from on-chain, this is ran automatically when SDK is initialized, hence
1231
+ * should only be ran manually when `dontCheckPastSwaps=true` is passed in the swapper options,
1232
+ * also deletes expired quotes
1233
+ *
1234
+ * @param chainId Optional chain identifier to only run swap sync for a single smart chain
1235
+ * @param signer Optional signer to only run swap sync for swaps initiated by this signer
1236
+ */
1237
+ async _syncSwaps(chainId, signer) {
1238
+ if (chainId == null) {
1239
+ await Promise.all(Object.keys(this._chains).map((chainId) => {
1240
+ return this.syncSwapsForChain(chainId, signer);
1241
+ }));
1242
+ }
1243
+ else {
1244
+ await this.syncSwapsForChain(chainId, signer);
1245
+ }
1246
+ }
1247
+ /**
1248
+ * Recovers swaps from on-chain historical data.
1249
+ *
1250
+ * Please note that the recovered swaps might not be complete (i.e. missing amounts or addresses), as some
1251
+ * of the swap data is purely off-chain and can never be recovered purely from on-chain data. This
1252
+ * functions tries to recover as much swap data as possible.
1253
+ *
1254
+ * @param chainId Smart chain identifier string to recover the swaps from
1255
+ * @param signer Signer address to recover the swaps for
1256
+ * @param startBlockheight Optional starting blockheight for swap data recovery, will only check swaps
1257
+ * initiated after this blockheight
1258
+ */
1259
+ async recoverSwaps(chainId, signer, startBlockheight) {
1260
+ //TODO: Recover swaps from all the known contract versions
1261
+ const { versionedContracts, unifiedSwapStorage, reviver, wrappers } = this._chains[chainId];
1262
+ const recoveredSwaps = [];
1263
+ let someVersionSupportsRecovery = false;
1264
+ const recoveredEscrowStates = {};
1265
+ const recoveredSpvStates = {};
1266
+ for (let contractVersion in versionedContracts) {
1267
+ const { swapContract, spvVaultContract } = versionedContracts[contractVersion];
1268
+ if (swapContract.getHistoricalSwaps == null ||
1269
+ (spvVaultContract != null && spvVaultContract.getHistoricalWithdrawalStates == null)) {
1270
+ this.logger.warn(`recoverSwaps(): Swap data recovery not supported on ${chainId}, with contract version ${contractVersion}`);
1271
+ continue;
1272
+ }
1273
+ someVersionSupportsRecovery = true;
1274
+ const { swaps } = await swapContract.getHistoricalSwaps(signer, startBlockheight);
1275
+ const spvVaultData = wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC] == null
1276
+ ? undefined
1277
+ : await spvVaultContract?.getHistoricalWithdrawalStates(signer, startBlockheight);
1278
+ for (let key in swaps)
1279
+ recoveredEscrowStates[key] = { ...swaps[key], contractVersion };
1280
+ if (spvVaultData != null)
1281
+ for (let key in spvVaultData.withdrawals)
1282
+ (recoveredSpvStates[contractVersion] ??= {})[key] = spvVaultData.withdrawals[key];
1283
+ }
1284
+ if (!someVersionSupportsRecovery)
1285
+ throw new Error(`Historical swap recovery is not supported for ${chainId}`);
1286
+ const escrowHashes = Object.keys(recoveredEscrowStates);
1287
+ for (let contractVersion in recoveredSpvStates)
1288
+ Object.keys(recoveredSpvStates[contractVersion]).forEach(btcTxId => escrowHashes.push(btcTxId));
1289
+ this.logger.debug(`recoverSwaps(): Loaded on-chain data for ${escrowHashes.length} swaps`);
1290
+ this.logger.debug(`recoverSwaps(): Fetching if swap escrowHashes are known: ${escrowHashes.join(", ")}`);
1291
+ const knownSwapsArray = await unifiedSwapStorage.query([[{ key: "escrowHash", value: escrowHashes }]], reviver);
1292
+ const knownSwaps = {};
1293
+ knownSwapsArray.forEach(val => {
1294
+ const escrowHash = val._getEscrowHash();
1295
+ if (escrowHash != null)
1296
+ knownSwaps[escrowHash] = val;
1297
+ });
1298
+ this.logger.debug(`recoverSwaps(): Fetched known swaps escrowHashes: ${Object.keys(knownSwaps).join(", ")}`);
1299
+ for (let escrowHash in recoveredEscrowStates) {
1300
+ const { init, state, contractVersion } = recoveredEscrowStates[escrowHash];
1301
+ const knownSwap = knownSwaps[escrowHash];
1302
+ const { swapContract } = versionedContracts[contractVersion];
1303
+ if (knownSwap == null) {
1304
+ if (init == null) {
1305
+ this.logger.warn(`recoverSwaps(escrow): Fetched ${escrowHash} swap state, but swap not found locally!`);
1306
+ continue;
1307
+ }
1308
+ }
1309
+ else if (knownSwap instanceof IEscrowSwap_1.IEscrowSwap) {
1310
+ this.logger.debug(`recoverSwaps(escrow): Forcibly updating ${escrowHash} swap: swap already known and in local storage!`);
1311
+ if ((knownSwap._contractVersion ?? "v1") !== contractVersion) {
1312
+ this.logger.debug(`recoverSwaps(escrow): Skipping ${escrowHash} swap: swap uses contract version ${knownSwap._contractVersion ?? "v1"}, but state comes from ${contractVersion}!`);
1313
+ continue;
1314
+ }
1315
+ if (await knownSwap._forciblySetOnchainState(state)) {
1316
+ await knownSwap._save();
1317
+ }
1318
+ continue;
1319
+ }
1320
+ else {
1321
+ this.logger.debug(`recoverSwaps(escrow): Skipping ${escrowHash} swap: swap already known and in local storage!`);
1322
+ continue;
1323
+ }
1324
+ const data = init.data;
1325
+ //Classify swap
1326
+ let swap;
1327
+ let typeIdentified = false;
1328
+ if (data.getType() === base_1.ChainSwapType.HTLC) {
1329
+ if (data.isOfferer(signer)) {
1330
+ //To BTCLN
1331
+ typeIdentified = true;
1332
+ const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isClaimer(val.getAddress(chainId)));
1333
+ swap = await wrappers[SwapType_1.SwapType.TO_BTCLN].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1334
+ }
1335
+ else if (data.isClaimer(signer)) {
1336
+ //From BTCLN
1337
+ typeIdentified = true;
1338
+ const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isOfferer(val.getAddress(chainId)));
1339
+ if (swapContract.supportsInitWithoutClaimer && wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO] != null) {
1340
+ swap = await wrappers[SwapType_1.SwapType.FROM_BTCLN_AUTO].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1341
+ }
1342
+ else {
1343
+ swap = await wrappers[SwapType_1.SwapType.FROM_BTCLN].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1344
+ }
1345
+ }
1346
+ }
1347
+ else if (data.getType() === base_1.ChainSwapType.CHAIN_NONCED) {
1348
+ //To BTC
1349
+ typeIdentified = true;
1350
+ const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isClaimer(val.getAddress(chainId)));
1351
+ swap = await wrappers[SwapType_1.SwapType.TO_BTC].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1352
+ }
1353
+ else if (data.getType() === base_1.ChainSwapType.CHAIN) {
1354
+ //From BTC
1355
+ typeIdentified = true;
1356
+ const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isOfferer(val.getAddress(chainId)));
1357
+ swap = await wrappers[SwapType_1.SwapType.FROM_BTC].recoverFromSwapDataAndState(init, state, contractVersion, lp);
1358
+ }
1359
+ if (swap != null) {
1360
+ recoveredSwaps.push(swap);
1361
+ }
1362
+ else {
1363
+ if (typeIdentified)
1364
+ this.logger.debug(`recoverSwaps(escrow): Swap data type correctly identified but swap returned is null for swap ${escrowHash}`);
1365
+ }
1366
+ }
1367
+ for (let contractVersion in recoveredSpvStates) {
1368
+ const { spvVaultContract } = versionedContracts[contractVersion];
1369
+ const spvVaultData = recoveredSpvStates[contractVersion];
1370
+ const vaultsData = await spvVaultContract.getMultipleVaultData(Object.keys(spvVaultData)
1371
+ .map(btcTxId => ({
1372
+ owner: spvVaultData[btcTxId].owner,
1373
+ vaultId: spvVaultData[btcTxId].vaultId
1374
+ })));
1375
+ for (let btcTxId in spvVaultData) {
1376
+ const state = spvVaultData[btcTxId];
1377
+ const knownSwap = knownSwaps[btcTxId];
1378
+ if (knownSwap != null) {
1379
+ if (knownSwap instanceof SpvFromBTCSwap_1.SpvFromBTCSwap) {
1380
+ this.logger.debug(`recoverSwaps(spv_vault): Forcibly updating ${btcTxId} swap: swap already known and in local storage!`);
1381
+ //TODO: Forcibly set on-chain state to the swap
1382
+ // if(await knownSwap._forciblySetOnchainState(state)) {
1383
+ // await knownSwap._save();
1384
+ // }
1385
+ continue;
1386
+ }
1387
+ else {
1388
+ this.logger.debug(`recoverSwaps(spv_vault): Skipping ${btcTxId} swap: swap already known and in local storage!`);
1389
+ continue;
1390
+ }
1391
+ }
1392
+ const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && state.owner.toLowerCase() === val.getAddress(chainId).toLowerCase());
1393
+ const swap = await wrappers[SwapType_1.SwapType.SPV_VAULT_FROM_BTC].recoverFromState(state, contractVersion, vaultsData[state.owner]?.[state.vaultId.toString(10)], lp);
1394
+ if (swap != null) {
1395
+ recoveredSwaps.push(swap);
1396
+ }
1397
+ else {
1398
+ this.logger.debug(`recoverSwaps(spv_vault): Swap data type correctly identified but swap returned is null for swap ${btcTxId}`);
1399
+ }
1400
+ }
1401
+ }
1402
+ this.logger.debug(`recoverSwaps(): Successfully recovered ${recoveredSwaps.length} swaps!`);
1403
+ return recoveredSwaps;
1404
+ }
1405
+ /**
1406
+ * Returns the {@link Token} object for a given token
1407
+ *
1408
+ * @param tickerOrAddress Token to return the object for, can use multiple formats:
1409
+ * - a) token ticker, such as `"BTC"`, `"SOL"`, etc.
1410
+ * - b) token ticker prefixed with smart chain identifier, such as `"SOLANA-SOL"`, `"SOLANA-USDC"`, etc.
1411
+ * - c) token address
1412
+ */
1413
+ getToken(tickerOrAddress) {
1414
+ //Btc tokens - BTC, BTCLN, BTC-LN
1415
+ if (tickerOrAddress === "BTC" || tickerOrAddress === "BITCOIN-BTC")
1416
+ return Token_1.BitcoinTokens.BTC;
1417
+ if (tickerOrAddress === "BTCLN" || tickerOrAddress === "BTC-LN" || tickerOrAddress === "LIGHTNING-BTC")
1418
+ return Token_1.BitcoinTokens.BTCLN;
1419
+ //Check if the ticker is in format <chainId>-<ticker>, i.e. SOLANA-USDC, STARKNET-WBTC
1420
+ if (tickerOrAddress.includes("-")) {
1421
+ const [chainId, ticker] = tickerOrAddress.split("-");
1422
+ const token = this._tokensByTicker[chainId]?.[ticker];
1423
+ if (token == null)
1424
+ throw new UserError_1.UserError(`Not found ticker: ${ticker} for chainId: ${chainId}`);
1425
+ return token;
1426
+ }
1427
+ const possibleTokens = [];
1428
+ for (let chainId in this._chains) {
1429
+ const chain = this._chains[chainId];
1430
+ if (chain.chainInterface.isValidToken(tickerOrAddress)) {
1431
+ //Try to find in known token addresses
1432
+ const token = this._tokens[chainId]?.[tickerOrAddress];
1433
+ if (token != null)
1434
+ return token;
1435
+ }
1436
+ else {
1437
+ //Check in known tickers
1438
+ const token = this._tokensByTicker[chainId]?.[tickerOrAddress];
1439
+ if (token != null)
1440
+ possibleTokens.push(token);
1441
+ }
1442
+ }
1443
+ if (possibleTokens.length === 0)
1444
+ throw new UserError_1.UserError(`Specified token address or ticker ${tickerOrAddress} not found!`);
1445
+ //In case we've found the token in multiple chains
1446
+ if (possibleTokens.length > 1)
1447
+ throw new UserError_1.UserError(`A ticker ${tickerOrAddress} has been found in multiple chains, narrow it down by using <chainId>-${tickerOrAddress} notation`);
1448
+ return possibleTokens[0];
1449
+ }
1450
+ /**
1451
+ * Creates a child swapper instance with a given smart chain
1452
+ *
1453
+ * @param chainIdentifier Smart chain identifier for the created child swapper instance
1454
+ */
1455
+ withChain(chainIdentifier) {
1456
+ if (this._chains[chainIdentifier] == null)
1457
+ throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
1458
+ return new SwapperWithChain_1.SwapperWithChain(this, chainIdentifier);
1459
+ }
1460
+ /**
1461
+ * Returns an array of all the supported smart chains
1462
+ */
1463
+ getSmartChains() {
1464
+ return Object.keys(this._chains);
1465
+ }
1466
+ /**
1467
+ * Returns whether the SDK supports a given swap type on a given chain based on currently known LPs
1468
+ *
1469
+ * @param chainId Smart chain identifier string
1470
+ * @param swapType Swap protocol type
1471
+ */
1472
+ supportsSwapType(chainId, swapType) {
1473
+ return (this._chains[chainId]?.wrappers[swapType] != null);
1474
+ }
1475
+ /**
1476
+ * Returns type of the swap based on input and output tokens specified
1477
+ *
1478
+ * @param srcToken Source token
1479
+ * @param dstToken Destination token
1480
+ */
1481
+ getSwapType(srcToken, dstToken) {
1482
+ if ((0, Token_1.isSCToken)(srcToken)) {
1483
+ if (!(0, Token_1.isBtcToken)(dstToken))
1484
+ throw new Error("Swap not supported");
1485
+ if (dstToken.lightning) {
1486
+ return SwapType_1.SwapType.TO_BTCLN;
1487
+ }
1488
+ else {
1489
+ return SwapType_1.SwapType.TO_BTC;
1490
+ }
1491
+ }
1492
+ else if ((0, Token_1.isBtcToken)(srcToken)) {
1493
+ if (!(0, Token_1.isSCToken)(dstToken))
1494
+ throw new Error("Swap not supported");
1495
+ if (srcToken.lightning) {
1496
+ if (this.supportsSwapType(dstToken.chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO)) {
1497
+ return SwapType_1.SwapType.FROM_BTCLN_AUTO;
1498
+ }
1499
+ else {
1500
+ return SwapType_1.SwapType.FROM_BTCLN;
1501
+ }
1502
+ }
1503
+ else {
1504
+ if (this.supportsSwapType(dstToken.chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC)) {
1505
+ return SwapType_1.SwapType.SPV_VAULT_FROM_BTC;
1506
+ }
1507
+ else {
1508
+ return SwapType_1.SwapType.FROM_BTC;
1509
+ }
1510
+ }
1511
+ }
1512
+ throw new Error("Swap not supported");
1513
+ }
1514
+ /**
1515
+ * Returns minimum/maximum limits for inputs and outputs for a swap between given tokens
1516
+ *
1517
+ * @param srcToken Source token
1518
+ * @param dstToken Destination token
1519
+ */
1520
+ getSwapLimits(srcToken, dstToken) {
1521
+ const swapType = this.getSwapType(srcToken, dstToken);
1522
+ const scToken = (0, Token_1.isSCToken)(srcToken) ? srcToken : (0, Token_1.isSCToken)(dstToken) ? dstToken : null;
1523
+ if (scToken == null)
1524
+ throw new Error("At least one token needs to be a smart chain token!");
1525
+ const result = {
1526
+ input: {},
1527
+ output: {}
1528
+ };
1529
+ for (let lp of this.intermediaryDiscovery.intermediaries) {
1530
+ const lpMinMax = lp.getSwapLimits(swapType, scToken.chainId, scToken.address);
1531
+ if (lpMinMax == null)
1532
+ continue;
1533
+ result.input.min = result.input.min == null ? lpMinMax.input.min : (0, Utils_1.bigIntMin)(result.input.min, lpMinMax.input.min);
1534
+ result.input.max = result.input.max == null ? lpMinMax.input.max : (0, Utils_1.bigIntMax)(result.input.max, lpMinMax.input.max);
1535
+ result.output.min = result.output.min == null ? lpMinMax.output.min : (0, Utils_1.bigIntMin)(result.output.min, lpMinMax.output.min);
1536
+ result.output.max = result.output.max == null ? lpMinMax.output.max : (0, Utils_1.bigIntMax)(result.output.max, lpMinMax.output.max);
1537
+ }
1538
+ return {
1539
+ input: {
1540
+ min: (0, TokenAmount_1.toTokenAmount)(result.input.min ?? 1n, srcToken, this.prices),
1541
+ max: result.input.max == null ? undefined : (0, TokenAmount_1.toTokenAmount)(result.input.max, srcToken, this.prices),
1542
+ },
1543
+ output: {
1544
+ min: (0, TokenAmount_1.toTokenAmount)(result.output.min ?? 1n, dstToken, this.prices),
1545
+ max: result.output.max == null ? undefined : (0, TokenAmount_1.toTokenAmount)(result.output.max, dstToken, this.prices),
1546
+ }
1547
+ };
1548
+ }
1549
+ /**
1550
+ * Returns an array of supported tokens either on the input or on the output of a swap
1551
+ *
1552
+ * @param input Whether to return input tokens or output tokens
1553
+ */
1554
+ getSupportedTokens(input) {
1555
+ const tokens = {};
1556
+ let lightning = false;
1557
+ let btc = false;
1558
+ this.intermediaryDiscovery.intermediaries.forEach(lp => {
1559
+ for (let swapType of [SwapType_1.SwapType.TO_BTC, SwapType_1.SwapType.TO_BTCLN, SwapType_1.SwapType.FROM_BTC, SwapType_1.SwapType.FROM_BTCLN, SwapType_1.SwapType.SPV_VAULT_FROM_BTC, SwapType_1.SwapType.FROM_BTCLN_AUTO]) {
1560
+ if (lp.services[swapType]?.chainTokens == null)
1561
+ continue;
1562
+ for (let chainId of this.getSmartChains()) {
1563
+ if (this.supportsSwapType(chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC) ? swapType === SwapType_1.SwapType.FROM_BTC : swapType === SwapType_1.SwapType.SPV_VAULT_FROM_BTC)
1564
+ continue;
1565
+ if (this.supportsSwapType(chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO) ? swapType === SwapType_1.SwapType.FROM_BTCLN : swapType === SwapType_1.SwapType.FROM_BTCLN_AUTO)
1566
+ continue;
1567
+ const chainTokens = lp.services[swapType]?.chainTokens?.[chainId];
1568
+ if (chainTokens == null)
1569
+ continue;
1570
+ for (let tokenAddress of chainTokens) {
1571
+ if (input) {
1572
+ if (swapType === SwapType_1.SwapType.TO_BTC || swapType === SwapType_1.SwapType.TO_BTCLN) {
1573
+ tokens[chainId] ??= new Set();
1574
+ tokens[chainId].add(tokenAddress);
1575
+ }
1576
+ if (swapType === SwapType_1.SwapType.FROM_BTCLN || swapType === SwapType_1.SwapType.FROM_BTCLN_AUTO) {
1577
+ lightning = true;
1578
+ }
1579
+ if (swapType === SwapType_1.SwapType.FROM_BTC || swapType === SwapType_1.SwapType.SPV_VAULT_FROM_BTC) {
1580
+ btc = true;
1581
+ }
1582
+ }
1583
+ else {
1584
+ if (swapType === SwapType_1.SwapType.FROM_BTCLN || swapType === SwapType_1.SwapType.FROM_BTC || swapType === SwapType_1.SwapType.SPV_VAULT_FROM_BTC || swapType === SwapType_1.SwapType.FROM_BTCLN_AUTO) {
1585
+ tokens[chainId] ??= new Set();
1586
+ tokens[chainId].add(tokenAddress);
1587
+ }
1588
+ if (swapType === SwapType_1.SwapType.TO_BTCLN) {
1589
+ lightning = true;
1590
+ }
1591
+ if (swapType === SwapType_1.SwapType.TO_BTC) {
1592
+ btc = true;
1593
+ }
1594
+ }
1595
+ }
1596
+ }
1597
+ }
1598
+ });
1599
+ const output = [];
1600
+ if (lightning)
1601
+ output.push(Token_1.BitcoinTokens.BTCLN);
1602
+ if (btc)
1603
+ output.push(Token_1.BitcoinTokens.BTC);
1604
+ for (let chainId in tokens) {
1605
+ tokens[chainId].forEach(tokenAddress => {
1606
+ const token = this._tokens?.[chainId]?.[tokenAddress];
1607
+ if (token != null)
1608
+ output.push(token);
1609
+ });
1610
+ }
1611
+ return output;
1612
+ }
1613
+ /**
1614
+ * Returns a set of supported tokens by all the intermediaries offering a specific swap service
1615
+ *
1616
+ * @param _swapType Swap service type to check supported tokens for
1617
+ */
1618
+ getSupportedTokensForSwapType(_swapType) {
1619
+ const tokens = {};
1620
+ this.intermediaryDiscovery.intermediaries.forEach(lp => {
1621
+ for (let chainId of this.getSmartChains()) {
1622
+ let swapType = _swapType;
1623
+ if (swapType === SwapType_1.SwapType.FROM_BTC && this.supportsSwapType(chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC))
1624
+ swapType = SwapType_1.SwapType.SPV_VAULT_FROM_BTC;
1625
+ if (swapType === SwapType_1.SwapType.FROM_BTCLN && this.supportsSwapType(chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO))
1626
+ swapType = SwapType_1.SwapType.FROM_BTCLN_AUTO;
1627
+ if (lp.services[swapType]?.chainTokens == null)
1628
+ break;
1629
+ const chainTokens = lp.services[swapType]?.chainTokens?.[chainId];
1630
+ if (chainTokens == null)
1631
+ continue;
1632
+ for (let tokenAddress of chainTokens) {
1633
+ tokens[chainId] ??= new Set();
1634
+ tokens[chainId].add(tokenAddress);
1635
+ }
1636
+ }
1637
+ });
1638
+ const output = [];
1639
+ for (let chainId in tokens) {
1640
+ tokens[chainId].forEach(tokenAddress => {
1641
+ const token = this._tokens?.[chainId]?.[tokenAddress];
1642
+ if (token != null)
1643
+ output.push(token);
1644
+ });
1645
+ }
1646
+ return output;
1647
+ }
1648
+ /**
1649
+ * Returns the set of supported token addresses by all the intermediaries we know of offering a specific swapType service
1650
+ *
1651
+ * @param chainIdentifier Chain identifier string
1652
+ * @param swapType Specific swap type for which to obtain supported tokens
1653
+ */
1654
+ getSupportedTokenAddresses(chainIdentifier, swapType) {
1655
+ const set = new Set();
1656
+ this.intermediaryDiscovery.intermediaries.forEach(lp => {
1657
+ const chainTokens = lp.services[swapType]?.chainTokens?.[chainIdentifier];
1658
+ if (chainTokens == null)
1659
+ return;
1660
+ chainTokens.forEach(token => set.add(token));
1661
+ });
1662
+ return set;
1663
+ }
1664
+ /**
1665
+ * Returns tokens that you can swap to (if input=true) from a given token,
1666
+ * or tokens that you can swap from (if input=false) to a given token
1667
+ */
1668
+ getSwapCounterTokens(token, input) {
1669
+ if ((0, Token_1.isSCToken)(token)) {
1670
+ const result = [];
1671
+ if (input) {
1672
+ //TO_BTC or TO_BTCLN
1673
+ if (this.getSupportedTokenAddresses(token.chainId, SwapType_1.SwapType.TO_BTCLN).has(token.address)) {
1674
+ result.push(Token_1.BitcoinTokens.BTCLN);
1675
+ }
1676
+ if (this.getSupportedTokenAddresses(token.chainId, SwapType_1.SwapType.TO_BTC).has(token.address)) {
1677
+ result.push(Token_1.BitcoinTokens.BTC);
1678
+ }
1679
+ }
1680
+ else {
1681
+ //FROM_BTC or FROM_BTCLN
1682
+ const fromLightningSwapType = this.supportsSwapType(token.chainId, SwapType_1.SwapType.FROM_BTCLN_AUTO) ? SwapType_1.SwapType.FROM_BTCLN_AUTO : SwapType_1.SwapType.FROM_BTCLN;
1683
+ if (this.getSupportedTokenAddresses(token.chainId, fromLightningSwapType).has(token.address)) {
1684
+ result.push(Token_1.BitcoinTokens.BTCLN);
1685
+ }
1686
+ const fromOnchainSwapType = this.supportsSwapType(token.chainId, SwapType_1.SwapType.SPV_VAULT_FROM_BTC) ? SwapType_1.SwapType.SPV_VAULT_FROM_BTC : SwapType_1.SwapType.FROM_BTC;
1687
+ if (this.getSupportedTokenAddresses(token.chainId, fromOnchainSwapType).has(token.address)) {
1688
+ result.push(Token_1.BitcoinTokens.BTC);
1689
+ }
1690
+ }
1691
+ return result;
1692
+ }
1693
+ else {
1694
+ if (input) {
1695
+ if (token.lightning) {
1696
+ return this.getSupportedTokensForSwapType(SwapType_1.SwapType.FROM_BTCLN);
1697
+ }
1698
+ else {
1699
+ return this.getSupportedTokensForSwapType(SwapType_1.SwapType.FROM_BTC);
1700
+ }
1701
+ }
1702
+ else {
1703
+ if (token.lightning) {
1704
+ return this.getSupportedTokensForSwapType(SwapType_1.SwapType.TO_BTCLN);
1705
+ }
1706
+ else {
1707
+ return this.getSupportedTokensForSwapType(SwapType_1.SwapType.TO_BTC);
1708
+ }
1709
+ }
1710
+ }
1711
+ }
1712
+ }
1713
+ exports.Swapper = Swapper;