@atomiqlabs/sdk 8.9.1 → 8.9.3

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