@atomiqlabs/sdk 7.0.11 → 8.0.7

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 (364) hide show
  1. package/README.md +45 -29
  2. package/dist/SmartChainAssets.d.ts +11 -3
  3. package/dist/SmartChainAssets.js +7 -3
  4. package/dist/bitcoin/BitcoinRpcWithAddressIndex.d.ts +68 -0
  5. package/dist/bitcoin/BitcoinRpcWithAddressIndex.js +2 -0
  6. package/dist/bitcoin/LightningNetworkApi.d.ts +12 -0
  7. package/dist/bitcoin/LightningNetworkApi.js +2 -0
  8. package/dist/bitcoin/coinselect2/accumulative.d.ts +6 -0
  9. package/dist/bitcoin/coinselect2/accumulative.js +52 -0
  10. package/dist/bitcoin/coinselect2/blackjack.d.ts +6 -0
  11. package/dist/bitcoin/coinselect2/blackjack.js +38 -0
  12. package/dist/bitcoin/coinselect2/index.d.ts +19 -0
  13. package/dist/bitcoin/coinselect2/index.js +69 -0
  14. package/dist/bitcoin/coinselect2/utils.d.ts +71 -0
  15. package/dist/bitcoin/coinselect2/utils.js +123 -0
  16. package/dist/bitcoin/mempool/MempoolApi.d.ts +350 -0
  17. package/dist/bitcoin/mempool/MempoolApi.js +311 -0
  18. package/dist/bitcoin/mempool/MempoolBitcoinBlock.d.ts +44 -0
  19. package/dist/bitcoin/mempool/MempoolBitcoinBlock.js +48 -0
  20. package/dist/bitcoin/mempool/MempoolBitcoinRpc.d.ts +119 -0
  21. package/dist/bitcoin/mempool/MempoolBitcoinRpc.js +361 -0
  22. package/dist/bitcoin/mempool/synchronizer/MempoolBtcRelaySynchronizer.d.ts +22 -0
  23. package/dist/bitcoin/mempool/synchronizer/MempoolBtcRelaySynchronizer.js +105 -0
  24. package/dist/bitcoin/wallet/BitcoinWallet.d.ts +93 -0
  25. package/dist/bitcoin/wallet/BitcoinWallet.js +273 -0
  26. package/dist/bitcoin/wallet/IBitcoinWallet.d.ts +28 -0
  27. package/dist/bitcoin/wallet/IBitcoinWallet.js +20 -0
  28. package/dist/bitcoin/wallet/MinimalBitcoinWalletInterface.d.ts +21 -0
  29. package/dist/bitcoin/wallet/MinimalBitcoinWalletInterface.js +2 -0
  30. package/dist/bitcoin/wallet/MinimalLightningNetworkWalletInterface.d.ts +7 -0
  31. package/dist/bitcoin/wallet/MinimalLightningNetworkWalletInterface.js +2 -0
  32. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.d.ts +40 -0
  33. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.js +86 -0
  34. package/dist/enums/FeeType.d.ts +8 -0
  35. package/dist/enums/FeeType.js +12 -0
  36. package/dist/enums/SwapAmountType.d.ts +8 -0
  37. package/dist/enums/SwapAmountType.js +12 -0
  38. package/dist/enums/SwapDirection.d.ts +8 -0
  39. package/dist/enums/SwapDirection.js +12 -0
  40. package/dist/enums/SwapType.d.ts +14 -0
  41. package/dist/enums/SwapType.js +18 -0
  42. package/dist/errors/IntermediaryError.d.ts +9 -0
  43. package/dist/errors/IntermediaryError.js +26 -0
  44. package/dist/errors/PaymentAuthError.d.ts +11 -0
  45. package/dist/errors/PaymentAuthError.js +23 -0
  46. package/dist/errors/RequestError.d.ts +18 -0
  47. package/dist/errors/RequestError.js +46 -0
  48. package/dist/errors/UserError.d.ts +7 -0
  49. package/dist/errors/UserError.js +15 -0
  50. package/dist/events/UnifiedSwapEventListener.d.ts +23 -0
  51. package/dist/events/UnifiedSwapEventListener.js +130 -0
  52. package/dist/http/HttpUtils.d.ts +27 -0
  53. package/dist/http/HttpUtils.js +91 -0
  54. package/dist/http/paramcoders/IParamReader.d.ts +8 -0
  55. package/dist/http/paramcoders/IParamReader.js +2 -0
  56. package/dist/http/paramcoders/ParamDecoder.d.ts +44 -0
  57. package/dist/http/paramcoders/ParamDecoder.js +132 -0
  58. package/dist/http/paramcoders/ParamEncoder.d.ts +20 -0
  59. package/dist/http/paramcoders/ParamEncoder.js +31 -0
  60. package/dist/http/paramcoders/SchemaVerifier.d.ts +26 -0
  61. package/dist/http/paramcoders/SchemaVerifier.js +145 -0
  62. package/dist/http/paramcoders/client/ResponseParamDecoder.d.ts +11 -0
  63. package/dist/http/paramcoders/client/ResponseParamDecoder.js +57 -0
  64. package/dist/http/paramcoders/client/StreamParamEncoder.d.ts +13 -0
  65. package/dist/http/paramcoders/client/StreamParamEncoder.js +26 -0
  66. package/dist/http/paramcoders/client/StreamingFetchPromise.d.ts +16 -0
  67. package/dist/http/paramcoders/client/StreamingFetchPromise.js +174 -0
  68. package/dist/index.d.ts +82 -4
  69. package/dist/index.js +128 -4
  70. package/dist/intermediaries/Intermediary.d.ts +111 -0
  71. package/dist/intermediaries/Intermediary.js +115 -0
  72. package/dist/intermediaries/IntermediaryDiscovery.d.ts +166 -0
  73. package/dist/intermediaries/IntermediaryDiscovery.js +390 -0
  74. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +436 -0
  75. package/dist/intermediaries/apis/IntermediaryAPI.js +600 -0
  76. package/dist/intermediaries/apis/TrustedIntermediaryAPI.d.ts +154 -0
  77. package/dist/intermediaries/apis/TrustedIntermediaryAPI.js +136 -0
  78. package/dist/lnurl/LNURL.d.ts +102 -0
  79. package/dist/lnurl/LNURL.js +321 -0
  80. package/dist/prices/RedundantSwapPrice.d.ts +89 -0
  81. package/dist/prices/RedundantSwapPrice.js +202 -0
  82. package/dist/prices/SingleSwapPrice.d.ts +31 -0
  83. package/dist/prices/SingleSwapPrice.js +41 -0
  84. package/dist/prices/SwapPriceWithChain.d.ts +70 -0
  85. package/dist/prices/SwapPriceWithChain.js +91 -0
  86. package/dist/prices/abstract/ICachedSwapPrice.d.ts +28 -0
  87. package/dist/prices/abstract/ICachedSwapPrice.js +62 -0
  88. package/dist/prices/abstract/IPriceProvider.d.ts +81 -0
  89. package/dist/prices/abstract/IPriceProvider.js +74 -0
  90. package/dist/prices/abstract/ISwapPrice.d.ts +117 -0
  91. package/dist/prices/abstract/ISwapPrice.js +219 -0
  92. package/dist/prices/providers/BinancePriceProvider.d.ts +16 -0
  93. package/dist/prices/providers/BinancePriceProvider.js +23 -0
  94. package/dist/prices/providers/CoinGeckoPriceProvider.d.ts +17 -0
  95. package/dist/prices/providers/CoinGeckoPriceProvider.js +23 -0
  96. package/dist/prices/providers/CoinPaprikaPriceProvider.d.ts +19 -0
  97. package/dist/prices/providers/CoinPaprikaPriceProvider.js +23 -0
  98. package/dist/prices/providers/CustomPriceProvider.d.ts +13 -0
  99. package/dist/prices/providers/CustomPriceProvider.js +24 -0
  100. package/dist/prices/providers/KrakenPriceProvider.d.ts +29 -0
  101. package/dist/prices/providers/KrakenPriceProvider.js +36 -0
  102. package/dist/prices/providers/OKXPriceProvider.d.ts +28 -0
  103. package/dist/prices/providers/OKXPriceProvider.js +23 -0
  104. package/dist/prices/providers/abstract/ExchangePriceProvider.d.ts +14 -0
  105. package/dist/prices/providers/abstract/ExchangePriceProvider.js +18 -0
  106. package/dist/prices/providers/abstract/HttpPriceProvider.d.ts +7 -0
  107. package/dist/prices/providers/abstract/HttpPriceProvider.js +12 -0
  108. package/dist/storage/IUnifiedStorage.d.ts +73 -0
  109. package/dist/storage/IUnifiedStorage.js +2 -0
  110. package/dist/storage/UnifiedSwapStorage.d.ts +82 -0
  111. package/dist/storage/UnifiedSwapStorage.js +83 -0
  112. package/dist/storage-browser/IndexedDBUnifiedStorage.d.ts +39 -0
  113. package/dist/storage-browser/IndexedDBUnifiedStorage.js +275 -0
  114. package/dist/{storage → storage-browser}/LocalStorageManager.d.ts +1 -0
  115. package/dist/{storage → storage-browser}/LocalStorageManager.js +2 -1
  116. package/dist/swapper/Swapper.d.ts +533 -0
  117. package/dist/swapper/Swapper.js +1566 -0
  118. package/dist/swapper/SwapperFactory.d.ts +87 -0
  119. package/dist/{SwapperFactory.js → swapper/SwapperFactory.js} +40 -22
  120. package/dist/swapper/SwapperUtils.d.ts +153 -0
  121. package/dist/swapper/SwapperUtils.js +420 -0
  122. package/dist/swapper/SwapperWithChain.d.ts +214 -0
  123. package/dist/swapper/SwapperWithChain.js +315 -0
  124. package/dist/swapper/SwapperWithSigner.d.ts +178 -0
  125. package/dist/swapper/SwapperWithSigner.js +172 -0
  126. package/dist/swaps/IAddressSwap.d.ts +13 -0
  127. package/dist/swaps/IAddressSwap.js +13 -0
  128. package/dist/swaps/IBTCWalletSwap.d.ts +55 -0
  129. package/dist/swaps/IBTCWalletSwap.js +17 -0
  130. package/dist/swaps/IClaimableSwap.d.ts +17 -0
  131. package/dist/swaps/IClaimableSwap.js +14 -0
  132. package/dist/swaps/IClaimableSwapWrapper.d.ts +5 -0
  133. package/dist/swaps/IClaimableSwapWrapper.js +2 -0
  134. package/dist/swaps/IRefundableSwap.d.ts +17 -0
  135. package/dist/swaps/IRefundableSwap.js +13 -0
  136. package/dist/swaps/ISwap.d.ts +207 -0
  137. package/dist/swaps/ISwap.js +264 -0
  138. package/dist/swaps/ISwapWithGasDrop.d.ts +15 -0
  139. package/dist/swaps/ISwapWithGasDrop.js +11 -0
  140. package/dist/swaps/ISwapWrapper.d.ts +153 -0
  141. package/dist/swaps/ISwapWrapper.js +227 -0
  142. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.d.ts +53 -0
  143. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.js +116 -0
  144. package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +70 -0
  145. package/dist/swaps/escrow_swaps/IEscrowSwap.js +132 -0
  146. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +85 -0
  147. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +122 -0
  148. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +86 -0
  149. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +115 -0
  150. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.d.ts +93 -0
  151. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +121 -0
  152. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.d.ts +45 -0
  153. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.js +65 -0
  154. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +263 -0
  155. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +933 -0
  156. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +110 -0
  157. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +307 -0
  158. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +236 -0
  159. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +898 -0
  160. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +125 -0
  161. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +393 -0
  162. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +245 -0
  163. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +841 -0
  164. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +120 -0
  165. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +294 -0
  166. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +228 -0
  167. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +721 -0
  168. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.d.ts +37 -0
  169. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +93 -0
  170. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.d.ts +86 -0
  171. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.js +213 -0
  172. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +170 -0
  173. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +520 -0
  174. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.d.ts +50 -0
  175. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.js +109 -0
  176. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +93 -0
  177. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +217 -0
  178. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +315 -0
  179. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +1098 -0
  180. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +125 -0
  181. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +631 -0
  182. package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +107 -0
  183. package/dist/swaps/trusted/ln/LnForGasSwap.js +343 -0
  184. package/dist/swaps/trusted/ln/LnForGasWrapper.d.ts +21 -0
  185. package/dist/swaps/trusted/ln/LnForGasWrapper.js +62 -0
  186. package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +164 -0
  187. package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +520 -0
  188. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.d.ts +48 -0
  189. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +74 -0
  190. package/dist/types/AmountData.d.ts +9 -0
  191. package/dist/types/AmountData.js +2 -0
  192. package/dist/types/CustomPriceFunction.d.ts +5 -0
  193. package/dist/types/CustomPriceFunction.js +2 -0
  194. package/dist/types/PriceInfoType.d.ts +28 -0
  195. package/dist/types/PriceInfoType.js +57 -0
  196. package/dist/types/SwapExecutionAction.d.ts +7 -0
  197. package/dist/types/SwapExecutionAction.js +2 -0
  198. package/dist/types/SwapWithSigner.d.ts +14 -0
  199. package/dist/types/SwapWithSigner.js +40 -0
  200. package/dist/types/Token.d.ts +53 -0
  201. package/dist/types/Token.js +58 -0
  202. package/dist/types/TokenAmount.d.ts +57 -0
  203. package/dist/types/TokenAmount.js +47 -0
  204. package/dist/types/fees/Fee.d.ts +49 -0
  205. package/dist/types/fees/Fee.js +2 -0
  206. package/dist/types/fees/FeeBreakdown.d.ts +10 -0
  207. package/dist/types/fees/FeeBreakdown.js +2 -0
  208. package/dist/types/fees/PercentagePPM.d.ts +15 -0
  209. package/dist/types/fees/PercentagePPM.js +17 -0
  210. package/dist/types/lnurl/LNURLPay.d.ts +54 -0
  211. package/dist/types/lnurl/LNURLPay.js +28 -0
  212. package/dist/types/lnurl/LNURLWithdraw.d.ts +42 -0
  213. package/dist/types/lnurl/LNURLWithdraw.js +24 -0
  214. package/dist/utils/AutomaticClockDriftCorrection.d.ts +1 -0
  215. package/dist/utils/AutomaticClockDriftCorrection.js +70 -0
  216. package/dist/utils/BitcoinUtils.d.ts +13 -0
  217. package/dist/utils/BitcoinUtils.js +98 -0
  218. package/dist/utils/BitcoinWalletUtils.d.ts +7 -0
  219. package/dist/utils/BitcoinWalletUtils.js +14 -0
  220. package/dist/utils/Logger.d.ts +7 -0
  221. package/dist/utils/Logger.js +12 -0
  222. package/dist/utils/RetryUtils.d.ts +21 -0
  223. package/dist/utils/RetryUtils.js +66 -0
  224. package/dist/utils/SwapUtils.d.ts +31 -0
  225. package/dist/utils/SwapUtils.js +18 -0
  226. package/dist/{Utils.d.ts → utils/TimeoutUtils.d.ts} +9 -3
  227. package/dist/utils/TimeoutUtils.js +55 -0
  228. package/dist/utils/TokenUtils.d.ts +11 -0
  229. package/dist/utils/TokenUtils.js +29 -0
  230. package/dist/utils/TypeUtils.d.ts +7 -0
  231. package/dist/utils/TypeUtils.js +2 -0
  232. package/dist/utils/Utils.d.ts +57 -0
  233. package/dist/utils/Utils.js +178 -0
  234. package/package.json +14 -6
  235. package/src/SmartChainAssets.ts +11 -3
  236. package/src/bitcoin/BitcoinRpcWithAddressIndex.ts +87 -0
  237. package/src/bitcoin/LightningNetworkApi.ts +16 -0
  238. package/src/bitcoin/coinselect2/accumulative.ts +68 -0
  239. package/src/bitcoin/coinselect2/blackjack.ts +49 -0
  240. package/src/bitcoin/coinselect2/index.ts +92 -0
  241. package/src/bitcoin/coinselect2/utils.ts +189 -0
  242. package/src/bitcoin/mempool/MempoolApi.ts +554 -0
  243. package/src/bitcoin/mempool/MempoolBitcoinBlock.ts +88 -0
  244. package/src/bitcoin/mempool/MempoolBitcoinRpc.ts +437 -0
  245. package/src/bitcoin/mempool/synchronizer/MempoolBtcRelaySynchronizer.ts +134 -0
  246. package/src/bitcoin/wallet/BitcoinWallet.ts +375 -0
  247. package/src/bitcoin/wallet/IBitcoinWallet.ts +44 -0
  248. package/src/bitcoin/wallet/MinimalBitcoinWalletInterface.ts +19 -0
  249. package/src/bitcoin/wallet/MinimalLightningNetworkWalletInterface.ts +7 -0
  250. package/src/bitcoin/wallet/SingleAddressBitcoinWallet.ts +108 -0
  251. package/src/enums/FeeType.ts +9 -0
  252. package/src/enums/SwapAmountType.ts +9 -0
  253. package/src/enums/SwapDirection.ts +9 -0
  254. package/src/enums/SwapType.ts +15 -0
  255. package/src/errors/IntermediaryError.ts +24 -0
  256. package/src/errors/PaymentAuthError.ts +26 -0
  257. package/src/errors/RequestError.ts +51 -0
  258. package/src/errors/UserError.ts +14 -0
  259. package/src/events/UnifiedSwapEventListener.ts +171 -0
  260. package/src/http/HttpUtils.ts +92 -0
  261. package/src/http/paramcoders/IParamReader.ts +10 -0
  262. package/src/http/paramcoders/ParamDecoder.ts +142 -0
  263. package/src/http/paramcoders/ParamEncoder.ts +37 -0
  264. package/src/http/paramcoders/SchemaVerifier.ts +153 -0
  265. package/src/http/paramcoders/client/ResponseParamDecoder.ts +58 -0
  266. package/src/http/paramcoders/client/StreamParamEncoder.ts +29 -0
  267. package/src/http/paramcoders/client/StreamingFetchPromise.ts +193 -0
  268. package/src/index.ts +102 -4
  269. package/src/intermediaries/Intermediary.ts +204 -0
  270. package/src/intermediaries/IntermediaryDiscovery.ts +485 -0
  271. package/src/intermediaries/apis/IntermediaryAPI.ts +940 -0
  272. package/src/intermediaries/apis/TrustedIntermediaryAPI.ts +257 -0
  273. package/src/lnurl/LNURL.ts +403 -0
  274. package/src/prices/RedundantSwapPrice.ts +245 -0
  275. package/src/prices/SingleSwapPrice.ts +47 -0
  276. package/src/prices/SwapPriceWithChain.ts +157 -0
  277. package/src/prices/abstract/ICachedSwapPrice.ts +86 -0
  278. package/src/prices/abstract/IPriceProvider.ts +128 -0
  279. package/src/prices/abstract/ISwapPrice.ts +328 -0
  280. package/src/prices/providers/BinancePriceProvider.ts +41 -0
  281. package/src/prices/providers/CoinGeckoPriceProvider.ts +40 -0
  282. package/src/prices/providers/CoinPaprikaPriceProvider.ts +44 -0
  283. package/src/prices/providers/CustomPriceProvider.ts +29 -0
  284. package/src/prices/providers/KrakenPriceProvider.ts +74 -0
  285. package/src/prices/providers/OKXPriceProvider.ts +53 -0
  286. package/src/prices/providers/abstract/ExchangePriceProvider.ts +29 -0
  287. package/src/prices/providers/abstract/HttpPriceProvider.ts +15 -0
  288. package/src/storage/IUnifiedStorage.ts +83 -0
  289. package/src/storage/UnifiedSwapStorage.ts +104 -0
  290. package/src/storage-browser/IndexedDBUnifiedStorage.ts +328 -0
  291. package/src/{storage → storage-browser}/LocalStorageManager.ts +2 -1
  292. package/src/swapper/Swapper.ts +2107 -0
  293. package/src/{SwapperFactory.ts → swapper/SwapperFactory.ts} +116 -75
  294. package/src/swapper/SwapperUtils.ts +510 -0
  295. package/src/swapper/SwapperWithChain.ts +464 -0
  296. package/src/swapper/SwapperWithSigner.ts +300 -0
  297. package/src/swaps/IAddressSwap.ts +20 -0
  298. package/src/swaps/IBTCWalletSwap.ts +77 -0
  299. package/src/swaps/IClaimableSwap.ts +30 -0
  300. package/src/swaps/IClaimableSwapWrapper.ts +9 -0
  301. package/src/swaps/IRefundableSwap.ts +29 -0
  302. package/src/swaps/ISwap.ts +490 -0
  303. package/src/swaps/ISwapWithGasDrop.ts +19 -0
  304. package/src/swaps/ISwapWrapper.ts +344 -0
  305. package/src/swaps/escrow_swaps/IEscrowSelfInitSwap.ts +168 -0
  306. package/src/swaps/escrow_swaps/IEscrowSwap.ts +197 -0
  307. package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +210 -0
  308. package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +150 -0
  309. package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +219 -0
  310. package/src/swaps/escrow_swaps/frombtc/IFromBTCWrapper.ts +84 -0
  311. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +1082 -0
  312. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +429 -0
  313. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +1078 -0
  314. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +549 -0
  315. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +974 -0
  316. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +443 -0
  317. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +860 -0
  318. package/src/swaps/escrow_swaps/tobtc/IToBTCWrapper.ts +104 -0
  319. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.ts +256 -0
  320. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +716 -0
  321. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.ts +151 -0
  322. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +299 -0
  323. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +1394 -0
  324. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +796 -0
  325. package/src/swaps/trusted/ln/LnForGasSwap.ts +402 -0
  326. package/src/swaps/trusted/ln/LnForGasWrapper.ts +70 -0
  327. package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +633 -0
  328. package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +110 -0
  329. package/src/types/AmountData.ts +9 -0
  330. package/src/types/CustomPriceFunction.ts +5 -0
  331. package/src/types/PriceInfoType.ts +67 -0
  332. package/src/types/SwapExecutionAction.ts +8 -0
  333. package/src/types/SwapWithSigner.ts +57 -0
  334. package/src/types/Token.ts +90 -0
  335. package/src/types/TokenAmount.ts +110 -0
  336. package/src/types/fees/Fee.ts +55 -0
  337. package/src/types/fees/FeeBreakdown.ts +11 -0
  338. package/src/types/fees/PercentagePPM.ts +24 -0
  339. package/src/types/lnurl/LNURLPay.ts +72 -0
  340. package/src/types/lnurl/LNURLWithdraw.ts +55 -0
  341. package/src/utils/AutomaticClockDriftCorrection.ts +71 -0
  342. package/src/utils/BitcoinUtils.ts +86 -0
  343. package/src/utils/BitcoinWalletUtils.ts +16 -0
  344. package/src/utils/Logger.ts +15 -0
  345. package/src/utils/RetryUtils.ts +71 -0
  346. package/src/utils/SwapUtils.ts +38 -0
  347. package/src/utils/TimeoutUtils.ts +50 -0
  348. package/src/utils/TokenUtils.ts +25 -0
  349. package/src/utils/TypeUtils.ts +9 -0
  350. package/src/utils/Utils.ts +182 -0
  351. package/dist/SwapperFactory.d.ts +0 -52
  352. package/dist/Utils.js +0 -37
  353. package/dist/fs-storage/FileSystemStorageManager.d.ts +0 -15
  354. package/dist/fs-storage/FileSystemStorageManager.js +0 -60
  355. package/dist/fs-storage/index.d.ts +0 -1
  356. package/dist/fs-storage/index.js +0 -17
  357. package/src/SmartChainAssets.js +0 -75
  358. package/src/SwapperFactory.js +0 -120
  359. package/src/Utils.js +0 -37
  360. package/src/Utils.ts +0 -31
  361. package/src/fs-storage/FileSystemStorageManager.ts +0 -71
  362. package/src/fs-storage/index.ts +0 -1
  363. package/src/index.js +0 -21
  364. package/src/storage/LocalStorageManager.js +0 -72
@@ -0,0 +1,2107 @@
1
+ import {ISwapPrice} from "../prices/abstract/ISwapPrice";
2
+ import {
3
+ BitcoinNetwork,
4
+ BtcRelay,
5
+ ChainData,
6
+ ChainSwapType,
7
+ ChainType,
8
+ Messenger,
9
+ RelaySynchronizer
10
+ } from "@atomiqlabs/base";
11
+ import {
12
+ InvoiceCreateService,
13
+ isInvoiceCreateService,
14
+ ToBTCLNOptions,
15
+ ToBTCLNWrapper
16
+ } from "../swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper";
17
+ import {ToBTCOptions, ToBTCWrapper} from "../swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper";
18
+ import {FromBTCLNOptions, FromBTCLNWrapper} from "../swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper";
19
+ import {FromBTCOptions, FromBTCWrapper} from "../swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper";
20
+ import {IntermediaryDiscovery, MultichainSwapBounds, SwapBounds} from "../intermediaries/IntermediaryDiscovery";
21
+ import {decode as bolt11Decode} from "@atomiqlabs/bolt11";
22
+ import {ISwap} from "../swaps/ISwap";
23
+ import {IntermediaryError} from "../errors/IntermediaryError";
24
+ import {SwapType} from "../enums/SwapType";
25
+ import {FromBTCLNSwap} from "../swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap";
26
+ import {FromBTCSwap} from "../swaps/escrow_swaps/frombtc/onchain/FromBTCSwap";
27
+ import {ToBTCLNSwap} from "../swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap";
28
+ import {ToBTCSwap} from "../swaps/escrow_swaps/tobtc/onchain/ToBTCSwap";
29
+ import {LnForGasWrapper} from "../swaps/trusted/ln/LnForGasWrapper";
30
+ import {LnForGasSwap} from "../swaps/trusted/ln/LnForGasSwap";
31
+ import {EventEmitter} from "events";
32
+ import {Intermediary} from "../intermediaries/Intermediary";
33
+ import {ISwapWrapper, WrapperCtorTokens} from "../swaps/ISwapWrapper";
34
+ import {bigIntCompare, bigIntMax, bigIntMin, fromDecimal, objectMap, randomBytes} from "../utils/Utils";
35
+ import {OutOfBoundsError} from "../errors/RequestError";
36
+ import {SwapperWithChain} from "./SwapperWithChain";
37
+ import {OnchainForGasSwap} from "../swaps/trusted/onchain/OnchainForGasSwap";
38
+ import {OnchainForGasWrapper} from "../swaps/trusted/onchain/OnchainForGasWrapper";
39
+ import {BTC_NETWORK, NETWORK, TEST_NETWORK} from "@scure/btc-signer/utils";
40
+ import {IUnifiedStorage, QueryParams} from "../storage/IUnifiedStorage";
41
+ import {
42
+ UnifiedSwapStorage,
43
+ UnifiedSwapStorageCompositeIndexes,
44
+ UnifiedSwapStorageIndexes
45
+ } from "../storage/UnifiedSwapStorage";
46
+ import {UnifiedSwapEventListener} from "../events/UnifiedSwapEventListener";
47
+ import {IToBTCSwap} from "../swaps/escrow_swaps/tobtc/IToBTCSwap";
48
+ import {SpvFromBTCOptions, SpvFromBTCWrapper} from "../swaps/spv_swaps/SpvFromBTCWrapper";
49
+ import {SpvFromBTCSwap} from "../swaps/spv_swaps/SpvFromBTCSwap";
50
+ import {SwapperUtils} from "./SwapperUtils";
51
+ import {FromBTCLNAutoOptions, FromBTCLNAutoWrapper} from "../swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper";
52
+ import {FromBTCLNAutoSwap} from "../swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap";
53
+ import {UserError} from "../errors/UserError";
54
+ import {SwapAmountType} from "../enums/SwapAmountType";
55
+ import {IClaimableSwap} from "../swaps/IClaimableSwap";
56
+ import {correctClock} from "../utils/AutomaticClockDriftCorrection";
57
+ import {isSwapType, SwapTypeMapping} from "../utils/SwapUtils";
58
+ import {MempoolBitcoinBlock} from "../bitcoin/mempool/MempoolBitcoinBlock";
59
+ import {MempoolBitcoinRpc} from "../bitcoin/mempool/MempoolBitcoinRpc";
60
+ import {MempoolApi} from "../bitcoin/mempool/MempoolApi";
61
+ import {MempoolBtcRelaySynchronizer} from "../bitcoin/mempool/synchronizer/MempoolBtcRelaySynchronizer";
62
+ import {IndexedDBUnifiedStorage} from "../storage-browser/IndexedDBUnifiedStorage";
63
+ import {TokenAmount, toTokenAmount} from "../types/TokenAmount";
64
+ import {BitcoinTokens, BtcToken, isBtcToken, isSCToken, SCToken, Token} from "../types/Token";
65
+ import {AmountData} from "../types/AmountData";
66
+ import {getLogger} from "../utils/Logger";
67
+ import {isLNURLWithdraw, LNURLWithdraw} from "../types/lnurl/LNURLWithdraw";
68
+ import {isLNURLPay, LNURLPay} from "../types/lnurl/LNURLPay";
69
+ import {tryWithRetries} from "../utils/RetryUtils";
70
+ import {NotNever} from "../utils/TypeUtils";
71
+
72
+ /**
73
+ * Configuration options for the Swapper
74
+ * @category Core
75
+ */
76
+ export type SwapperOptions = {
77
+ intermediaryUrl?: string | string[],
78
+ registryUrl?: string,
79
+
80
+ bitcoinNetwork?: BitcoinNetwork,
81
+
82
+ getRequestTimeout?: number,
83
+ postRequestTimeout?: number,
84
+ defaultAdditionalParameters?: {[key: string]: any},
85
+ storagePrefix?: string
86
+ defaultTrustedIntermediaryUrl?: string,
87
+
88
+ swapStorage?: <T extends ChainType>(chainId: T["ChainId"]) => IUnifiedStorage<UnifiedSwapStorageIndexes, UnifiedSwapStorageCompositeIndexes>,
89
+
90
+ noTimers?: boolean,
91
+ noEvents?: boolean,
92
+ noSwapCache?: boolean,
93
+ dontCheckPastSwaps?: boolean,
94
+ dontFetchLPs?: boolean,
95
+ saveUninitializedSwaps?: boolean, //automatically persist all created swaps - by default only initiated swaps are persisted
96
+ automaticClockDriftCorrection?: boolean
97
+ };
98
+
99
+ /**
100
+ * Type representing multiple blockchain configurations
101
+ * @category Core
102
+ */
103
+ export type MultiChain = {
104
+ [chainIdentifier in string]: ChainType;
105
+ };
106
+
107
+ type ChainSpecificData<T extends ChainType> = {
108
+ wrappers: {
109
+ [SwapType.TO_BTCLN]: ToBTCLNWrapper<T>,
110
+ [SwapType.TO_BTC]: ToBTCWrapper<T>,
111
+ [SwapType.FROM_BTCLN]: FromBTCLNWrapper<T>,
112
+ [SwapType.FROM_BTC]: FromBTCWrapper<T>,
113
+ [SwapType.TRUSTED_FROM_BTCLN]: LnForGasWrapper<T>,
114
+ [SwapType.TRUSTED_FROM_BTC]: OnchainForGasWrapper<T>,
115
+ [SwapType.SPV_VAULT_FROM_BTC]: SpvFromBTCWrapper<T>,
116
+ [SwapType.FROM_BTCLN_AUTO]: FromBTCLNAutoWrapper<T>
117
+ }
118
+ chainEvents: T["Events"],
119
+ swapContract: T["Contract"],
120
+ spvVaultContract: T["SpvVaultContract"],
121
+ chainInterface: T["ChainInterface"],
122
+ btcRelay: BtcRelay<any, T["TX"], MempoolBitcoinBlock, T["Signer"]>,
123
+ synchronizer: RelaySynchronizer<any, T["TX"], MempoolBitcoinBlock>,
124
+ unifiedChainEvents: UnifiedSwapEventListener<T>,
125
+ unifiedSwapStorage: UnifiedSwapStorage<T>,
126
+ reviver: (val: any) => ISwap<T>
127
+ };
128
+
129
+ type MultiChainData<T extends MultiChain> = {
130
+ [chainIdentifier in keyof T]: ChainSpecificData<T[chainIdentifier]>
131
+ };
132
+
133
+ type CtorMultiChainData<T extends MultiChain> = {
134
+ [chainIdentifier in keyof T]: ChainData<T[chainIdentifier]>
135
+ };
136
+
137
+ /**
138
+ * Type extracting chain identifiers from a MultiChain type
139
+ * @category Core
140
+ */
141
+ export type ChainIds<T extends MultiChain> = keyof T & string;
142
+
143
+ /**
144
+ * Type helper to check if a chain supports a specific swap type
145
+ * @category Core
146
+ */
147
+ export type SupportsSwapType<
148
+ C extends ChainType,
149
+ Type extends SwapType
150
+ > = Type extends SwapType.SPV_VAULT_FROM_BTC ?
151
+ NotNever<C["SpvVaultContract"]> :
152
+ Type extends (SwapType.TRUSTED_FROM_BTCLN | SwapType.TRUSTED_FROM_BTC) ?
153
+ true :
154
+ Type extends SwapType.FROM_BTCLN_AUTO ? (C["Contract"]["supportsInitWithoutClaimer"] extends true ? true : false) :
155
+ NotNever<C["Contract"]>;
156
+
157
+ /**
158
+ * Core orchestrator for all swap operations with multi-chain support
159
+ * @category Core
160
+ */
161
+ export class Swapper<T extends MultiChain> extends EventEmitter<{
162
+ lpsRemoved: [Intermediary[]],
163
+ lpsAdded: [Intermediary[]],
164
+ swapState: [ISwap],
165
+ swapLimitsChanged: []
166
+ }> {
167
+ protected readonly logger = getLogger(this.constructor.name+": ");
168
+ protected readonly swapStateListener: (swap: ISwap) => void;
169
+
170
+ private defaultTrustedIntermediary?: Intermediary;
171
+ private readonly _bitcoinNetwork: BitcoinNetwork;
172
+ private readonly options: SwapperOptions;
173
+
174
+ readonly chains: MultiChainData<T>;
175
+
176
+ readonly prices: ISwapPrice<T>;
177
+ readonly intermediaryDiscovery: IntermediaryDiscovery;
178
+ readonly mempoolApi: MempoolApi;
179
+ readonly bitcoinRpc: MempoolBitcoinRpc;
180
+ readonly bitcoinNetwork: BTC_NETWORK;
181
+ readonly messenger: Messenger;
182
+
183
+ readonly Utils: SwapperUtils<T>;
184
+
185
+ readonly tokens: {
186
+ [chainId: string]: {
187
+ [tokenAddress: string]: SCToken
188
+ }
189
+ };
190
+ readonly tokensByTicker: {
191
+ [chainId: string]: {
192
+ [tokenTicker: string]: SCToken
193
+ }
194
+ };
195
+
196
+ constructor(
197
+ bitcoinRpc: MempoolBitcoinRpc,
198
+ chainsData: CtorMultiChainData<T>,
199
+ pricing: ISwapPrice<T>,
200
+ tokens: WrapperCtorTokens<T>,
201
+ messenger: Messenger,
202
+ options?: SwapperOptions
203
+ ) {
204
+ super();
205
+ const storagePrefix = options?.storagePrefix ?? "atomiq-";
206
+
207
+ options ??= {};
208
+ options.bitcoinNetwork = options.bitcoinNetwork==null ? BitcoinNetwork.TESTNET : options.bitcoinNetwork;
209
+ const swapStorage = options.swapStorage ??= (name: string) => new IndexedDBUnifiedStorage(name);
210
+
211
+ this.options = options;
212
+
213
+ this._bitcoinNetwork = options.bitcoinNetwork;
214
+ this.bitcoinNetwork = options.bitcoinNetwork===BitcoinNetwork.MAINNET ? NETWORK :
215
+ (options.bitcoinNetwork===BitcoinNetwork.TESTNET || options.bitcoinNetwork===BitcoinNetwork.TESTNET4) ? TEST_NETWORK : {
216
+ bech32: 'bcrt',
217
+ pubKeyHash: 111,
218
+ scriptHash: 196,
219
+ wif: 239
220
+ };
221
+ this.Utils = new SwapperUtils(this);
222
+
223
+ this.prices = pricing;
224
+ this.bitcoinRpc = bitcoinRpc;
225
+ this.mempoolApi = bitcoinRpc.api;
226
+ this.messenger = messenger;
227
+
228
+ this.tokens = {};
229
+ this.tokensByTicker = {};
230
+ for(let tokenData of tokens) {
231
+ for(let chainId in tokenData.chains) {
232
+ const chainData = tokenData.chains[chainId]!;
233
+ this.tokens[chainId] ??= {};
234
+ this.tokensByTicker[chainId] ??= {};
235
+ this.tokens[chainId][chainData.address] = this.tokensByTicker[chainId][tokenData.ticker] = {
236
+ chain: "SC",
237
+ chainId,
238
+ ticker: tokenData.ticker,
239
+ name: tokenData.name,
240
+ decimals: chainData.decimals,
241
+ displayDecimals: chainData.displayDecimals,
242
+ address: chainData.address
243
+ }
244
+ }
245
+ }
246
+
247
+ this.swapStateListener = (swap: ISwap) => {
248
+ this.emit("swapState", swap);
249
+ };
250
+
251
+ this.chains = objectMap<CtorMultiChainData<T>, MultiChainData<T>>(chainsData, <InputKey extends keyof CtorMultiChainData<T>>(chainData: CtorMultiChainData<T>[InputKey], key: string) => {
252
+ const {
253
+ swapContract, chainEvents, btcRelay,
254
+ chainInterface, spvVaultContract, spvVaultWithdrawalDataConstructor
255
+ } = chainData;
256
+ const synchronizer = new MempoolBtcRelaySynchronizer(btcRelay, bitcoinRpc);
257
+
258
+ const storageHandler = swapStorage(storagePrefix + chainData.chainId);
259
+ const unifiedSwapStorage = new UnifiedSwapStorage<T[InputKey]>(storageHandler, this.options.noSwapCache);
260
+ const unifiedChainEvents = new UnifiedSwapEventListener<T[InputKey]>(unifiedSwapStorage, chainEvents);
261
+
262
+ const wrappers: any = {};
263
+
264
+ wrappers[SwapType.TO_BTCLN] = new ToBTCLNWrapper<T[InputKey]>(
265
+ key,
266
+ unifiedSwapStorage,
267
+ unifiedChainEvents,
268
+ chainInterface,
269
+ swapContract,
270
+ pricing,
271
+ tokens,
272
+ chainData.swapDataConstructor,
273
+ {
274
+ getRequestTimeout: this.options.getRequestTimeout,
275
+ postRequestTimeout: this.options.postRequestTimeout,
276
+ }
277
+ );
278
+ wrappers[SwapType.TO_BTC] = new ToBTCWrapper<T[InputKey]>(
279
+ key,
280
+ unifiedSwapStorage,
281
+ unifiedChainEvents,
282
+ chainInterface,
283
+ swapContract,
284
+ pricing,
285
+ tokens,
286
+ chainData.swapDataConstructor,
287
+ this.bitcoinRpc,
288
+ {
289
+ getRequestTimeout: this.options.getRequestTimeout,
290
+ postRequestTimeout: this.options.postRequestTimeout,
291
+ bitcoinNetwork: this.bitcoinNetwork
292
+ }
293
+ );
294
+ wrappers[SwapType.FROM_BTCLN] = new FromBTCLNWrapper<T[InputKey]>(
295
+ key,
296
+ unifiedSwapStorage,
297
+ unifiedChainEvents,
298
+ chainInterface,
299
+ swapContract,
300
+ pricing,
301
+ tokens,
302
+ chainData.swapDataConstructor,
303
+ bitcoinRpc,
304
+ {
305
+ getRequestTimeout: this.options.getRequestTimeout,
306
+ postRequestTimeout: this.options.postRequestTimeout,
307
+ unsafeSkipLnNodeCheck: this._bitcoinNetwork===BitcoinNetwork.TESTNET4 || this._bitcoinNetwork===BitcoinNetwork.REGTEST
308
+ }
309
+ );
310
+ wrappers[SwapType.FROM_BTC] = new FromBTCWrapper<T[InputKey]>(
311
+ key,
312
+ unifiedSwapStorage,
313
+ unifiedChainEvents,
314
+ chainInterface,
315
+ swapContract,
316
+ pricing,
317
+ tokens,
318
+ chainData.swapDataConstructor,
319
+ btcRelay,
320
+ synchronizer,
321
+ this.bitcoinRpc,
322
+ {
323
+ getRequestTimeout: this.options.getRequestTimeout,
324
+ postRequestTimeout: this.options.postRequestTimeout,
325
+ bitcoinNetwork: this.bitcoinNetwork
326
+ }
327
+ );
328
+ wrappers[SwapType.TRUSTED_FROM_BTCLN] = new LnForGasWrapper<T[InputKey]>(
329
+ key,
330
+ unifiedSwapStorage,
331
+ unifiedChainEvents,
332
+ chainInterface,
333
+ pricing,
334
+ tokens,
335
+ {
336
+ getRequestTimeout: this.options.getRequestTimeout,
337
+ postRequestTimeout: this.options.postRequestTimeout
338
+ }
339
+ );
340
+ wrappers[SwapType.TRUSTED_FROM_BTC] = new OnchainForGasWrapper<T[InputKey]>(
341
+ key,
342
+ unifiedSwapStorage,
343
+ unifiedChainEvents,
344
+ chainInterface,
345
+ pricing,
346
+ tokens,
347
+ bitcoinRpc,
348
+ {
349
+ getRequestTimeout: this.options.getRequestTimeout,
350
+ postRequestTimeout: this.options.postRequestTimeout,
351
+ bitcoinNetwork: this.bitcoinNetwork
352
+ }
353
+ );
354
+
355
+ if(spvVaultContract!=null) {
356
+ wrappers[SwapType.SPV_VAULT_FROM_BTC] = new SpvFromBTCWrapper<T[InputKey]>(
357
+ key,
358
+ unifiedSwapStorage,
359
+ unifiedChainEvents,
360
+ chainInterface,
361
+ spvVaultContract,
362
+ pricing,
363
+ tokens,
364
+ spvVaultWithdrawalDataConstructor,
365
+ btcRelay,
366
+ synchronizer,
367
+ bitcoinRpc,
368
+ {
369
+ getRequestTimeout: this.options.getRequestTimeout,
370
+ postRequestTimeout: this.options.postRequestTimeout,
371
+ bitcoinNetwork: this.bitcoinNetwork
372
+ }
373
+ );
374
+ }
375
+
376
+ if(swapContract.supportsInitWithoutClaimer) {
377
+ wrappers[SwapType.FROM_BTCLN_AUTO] = new FromBTCLNAutoWrapper<T[InputKey]>(
378
+ key,
379
+ unifiedSwapStorage,
380
+ unifiedChainEvents,
381
+ chainInterface,
382
+ swapContract,
383
+ pricing,
384
+ tokens,
385
+ chainData.swapDataConstructor,
386
+ bitcoinRpc,
387
+ this.messenger,
388
+ {
389
+ getRequestTimeout: this.options.getRequestTimeout,
390
+ postRequestTimeout: this.options.postRequestTimeout,
391
+ unsafeSkipLnNodeCheck: this._bitcoinNetwork===BitcoinNetwork.TESTNET4 || this._bitcoinNetwork===BitcoinNetwork.REGTEST
392
+ }
393
+ );
394
+ }
395
+
396
+ Object.keys(wrappers).forEach(key => wrappers[key].events.on("swapState", this.swapStateListener));
397
+
398
+ const reviver = (val: any) => {
399
+ const wrapper = wrappers[val.type];
400
+ if(wrapper==null) return null;
401
+ return new wrapper.swapDeserializer(wrapper, val);
402
+ };
403
+
404
+ return {
405
+ chainEvents,
406
+ spvVaultContract,
407
+ swapContract,
408
+ chainInterface,
409
+ btcRelay,
410
+ synchronizer,
411
+
412
+ wrappers,
413
+
414
+ unifiedChainEvents,
415
+ unifiedSwapStorage,
416
+
417
+ reviver
418
+ }
419
+ });
420
+
421
+ const contracts = objectMap(chainsData, (data) => data.swapContract);
422
+ if(options.intermediaryUrl!=null) {
423
+ this.intermediaryDiscovery = new IntermediaryDiscovery(contracts, options.registryUrl, Array.isArray(options.intermediaryUrl) ? options.intermediaryUrl : [options.intermediaryUrl], options.getRequestTimeout);
424
+ } else {
425
+ this.intermediaryDiscovery = new IntermediaryDiscovery(contracts, options.registryUrl, undefined, options.getRequestTimeout);
426
+ }
427
+
428
+ this.intermediaryDiscovery.on("removed", (intermediaries: Intermediary[]) => {
429
+ this.emit("lpsRemoved", intermediaries);
430
+ });
431
+
432
+ this.intermediaryDiscovery.on("added", (intermediaries: Intermediary[]) => {
433
+ this.emit("lpsAdded", intermediaries);
434
+ });
435
+ }
436
+
437
+ private async _init(): Promise<void> {
438
+ this.logger.debug("init(): Initializing swapper, sdk-lib version 16.1.3");
439
+
440
+ const abortController = new AbortController();
441
+
442
+ const promises: Promise<void>[] = [];
443
+ let automaticClockDriftCorrectionPromise: Promise<void> | undefined = undefined;
444
+ if(this.options.automaticClockDriftCorrection) {
445
+ promises.push(automaticClockDriftCorrectionPromise = tryWithRetries(correctClock, undefined, undefined, abortController.signal).catch((err) => {
446
+ abortController.abort(err);
447
+ }));
448
+ }
449
+
450
+ this.logger.debug("init(): Initializing intermediary discovery");
451
+ if(!this.options.dontFetchLPs) promises.push(this.intermediaryDiscovery.init(abortController.signal).catch(err => {
452
+ if(abortController.signal.aborted) return;
453
+ this.logger.error("init(): Failed to fetch intermediaries/LPs: ", err);
454
+ }));
455
+
456
+ if(this.options.defaultTrustedIntermediaryUrl!=null) {
457
+ promises.push(
458
+ this.intermediaryDiscovery.getIntermediary(this.options.defaultTrustedIntermediaryUrl, abortController.signal)
459
+ .then(val => {
460
+ if(val==null) throw new Error("Cannot get trusted LP");
461
+ this.defaultTrustedIntermediary = val;
462
+ })
463
+ .catch(err => {
464
+ if(abortController.signal.aborted) return;
465
+ this.logger.error("init(): Failed to contact trusted LP url: ", err);
466
+ })
467
+ );
468
+ }
469
+
470
+ if(automaticClockDriftCorrectionPromise!=null) {
471
+ //We should await the promises here before checking the swaps
472
+ await automaticClockDriftCorrectionPromise;
473
+ }
474
+
475
+ const chainPromises = [];
476
+ for(let chainIdentifier in this.chains) {
477
+ chainPromises.push((async() => {
478
+ const {
479
+ swapContract,
480
+ unifiedChainEvents,
481
+ unifiedSwapStorage,
482
+ wrappers,
483
+ reviver
484
+ } = this.chains[chainIdentifier];
485
+ await swapContract.start();
486
+ this.logger.debug("init(): Intialized swap contract: "+chainIdentifier);
487
+
488
+ await unifiedSwapStorage.init();
489
+ if(unifiedSwapStorage.storage instanceof IndexedDBUnifiedStorage) {
490
+ //Try to migrate the data here
491
+ const storagePrefix = chainIdentifier==="SOLANA" ?
492
+ "SOLv4-"+this._bitcoinNetwork+"-Swaps-" :
493
+ "atomiqsdk-"+this._bitcoinNetwork+chainIdentifier+"-Swaps-";
494
+ await unifiedSwapStorage.storage.tryMigrate(
495
+ [
496
+ [storagePrefix+"FromBTC", SwapType.FROM_BTC],
497
+ [storagePrefix+"FromBTCLN", SwapType.FROM_BTCLN],
498
+ [storagePrefix+"ToBTC", SwapType.TO_BTC],
499
+ [storagePrefix+"ToBTCLN", SwapType.TO_BTCLN]
500
+ ],
501
+ (obj: any) => {
502
+ const swap = reviver(obj);
503
+ if(swap.randomNonce==null) {
504
+ const oldIdentifierHash = swap.getId();
505
+ swap.randomNonce = randomBytes(16).toString("hex");
506
+ const newIdentifierHash = swap.getId();
507
+ this.logger.info("init(): Found older swap version without randomNonce, replacing, old hash: "+oldIdentifierHash+
508
+ " new hash: "+newIdentifierHash);
509
+ }
510
+ return swap;
511
+ }
512
+ )
513
+ }
514
+
515
+ if(!this.options.noEvents) await unifiedChainEvents.start();
516
+ this.logger.debug("init(): Intialized events: "+chainIdentifier);
517
+
518
+ for(let key in wrappers) {
519
+ // this.logger.debug("init(): Initializing "+SwapType[key]+": "+chainIdentifier);
520
+ await wrappers[key as unknown as SwapType].init(this.options.noTimers, this.options.dontCheckPastSwaps);
521
+ }
522
+ })());
523
+ }
524
+ await Promise.all(chainPromises);
525
+
526
+ await Promise.all(promises);
527
+
528
+ this.logger.debug("init(): Initializing messenger");
529
+ await this.messenger.init();
530
+ }
531
+
532
+ private initPromise?: Promise<void>;
533
+ private initialized: boolean = false;
534
+
535
+ /**
536
+ * Initializes the swap storage and loads existing swaps, needs to be called before any other action
537
+ */
538
+ async init(): Promise<void> {
539
+ if(this.initialized) return;
540
+ if(this.initPromise!=null) await this.initPromise;
541
+
542
+ try {
543
+ const promise = this._init();
544
+ this.initPromise = promise;
545
+ await promise;
546
+ delete this.initPromise;
547
+ this.initialized = true;
548
+ } catch (e) {
549
+ delete this.initPromise;
550
+ throw e;
551
+ }
552
+ }
553
+
554
+ /**
555
+ * Stops listening for onchain events and closes this Swapper instance
556
+ */
557
+ async stop() {
558
+ if(this.initPromise) await this.initPromise;
559
+ for(let chainIdentifier in this.chains) {
560
+ const {
561
+ wrappers,
562
+ unifiedChainEvents
563
+ } = this.chains[chainIdentifier];
564
+ for(let key in wrappers) {
565
+ const wrapper = wrappers[key as unknown as SwapType];
566
+ wrapper.events.removeListener("swapState", this.swapStateListener);
567
+ await wrapper.stop();
568
+ }
569
+ await unifiedChainEvents.stop();
570
+ await this.messenger.stop();
571
+ }
572
+ this.initialized = false;
573
+ }
574
+
575
+ /**
576
+ * Creates swap & handles intermediary, quote selection
577
+ *
578
+ * @param chainIdentifier
579
+ * @param create Callback to create the
580
+ * @param amountData Amount data as passed to the function
581
+ * @param swapType Swap type of the execution
582
+ * @param maxWaitTimeMS Maximum waiting time after the first intermediary returns the quote
583
+ * @private
584
+ * @throws {Error} when no intermediary was found
585
+ * @throws {Error} if the chain with the provided identifier cannot be found
586
+ */
587
+ private async createSwap<ChainIdentifier extends ChainIds<T>, S extends ISwap<T[ChainIdentifier]>>(
588
+ chainIdentifier: ChainIdentifier,
589
+ create: (candidates: Intermediary[], abortSignal: AbortSignal, chain: ChainSpecificData<T[ChainIdentifier]>) => Promise<{
590
+ quote: Promise<S>,
591
+ intermediary: Intermediary
592
+ }[]>,
593
+ amountData: AmountData,
594
+ swapType: SwapType,
595
+ maxWaitTimeMS: number = 2000
596
+ ): Promise<S> {
597
+ if(!this.initialized) throw new Error("Swapper not initialized, init first with swapper.init()!");
598
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
599
+ let candidates: Intermediary[];
600
+
601
+ const inBtc: boolean = swapType===SwapType.TO_BTCLN || swapType===SwapType.TO_BTC ? !amountData.exactIn : amountData.exactIn;
602
+
603
+ if(!inBtc) {
604
+ //Get candidates not based on the amount
605
+ candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token);
606
+ } else {
607
+ candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token, amountData.amount);
608
+ }
609
+
610
+ let swapLimitsChanged = false;
611
+
612
+ if(candidates.length===0) {
613
+ this.logger.warn("createSwap(): No valid intermediary found, reloading intermediary database...");
614
+ await this.intermediaryDiscovery.reloadIntermediaries();
615
+ swapLimitsChanged = true;
616
+
617
+ if(!inBtc) {
618
+ //Get candidates not based on the amount
619
+ candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token);
620
+ } else {
621
+ candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token, amountData.amount);
622
+
623
+ if(candidates.length===0) {
624
+ const min = this.intermediaryDiscovery.getSwapMinimum(chainIdentifier, swapType, amountData.token);
625
+ const max = this.intermediaryDiscovery.getSwapMaximum(chainIdentifier, swapType, amountData.token);
626
+ if(min!=null && max!=null) {
627
+ if(amountData.amount < BigInt(min)) throw new OutOfBoundsError("Amount too low!", 200, BigInt(min), BigInt(max));
628
+ if(amountData.amount > BigInt(max)) throw new OutOfBoundsError("Amount too high!", 200, BigInt(min), BigInt(max));
629
+ }
630
+ }
631
+ }
632
+
633
+ if(candidates.length===0) throw new Error("No intermediary found!");
634
+ }
635
+
636
+
637
+ const abortController = new AbortController();
638
+ this.logger.debug("createSwap() Swap candidates: ", candidates.map(lp => lp.url).join());
639
+ const quotePromises: {quote: Promise<S>, intermediary: Intermediary}[] = await create(candidates, abortController.signal, this.chains[chainIdentifier]);
640
+
641
+ const promiseAll = new Promise<{
642
+ quote: S,
643
+ intermediary: Intermediary
644
+ }[]>((resolve, reject) => {
645
+ let min: bigint;
646
+ let max: bigint;
647
+ let error: Error;
648
+ let numResolved = 0;
649
+ let quotes: {
650
+ quote: S,
651
+ intermediary: Intermediary
652
+ }[] = [];
653
+ let timeout: NodeJS.Timeout;
654
+
655
+ quotePromises.forEach(data => {
656
+ data.quote.then(quote => {
657
+ if(numResolved===0) {
658
+ timeout = setTimeout(() => {
659
+ abortController.abort(new Error("Timed out waiting for quote!"));
660
+ resolve(quotes);
661
+ }, maxWaitTimeMS);
662
+ }
663
+ numResolved++;
664
+ quotes.push({
665
+ quote,
666
+ intermediary: data.intermediary
667
+ });
668
+ if(numResolved===quotePromises.length) {
669
+ clearTimeout(timeout);
670
+ resolve(quotes);
671
+ return;
672
+ }
673
+ }).catch(e => {
674
+ numResolved++;
675
+ if(e instanceof IntermediaryError) {
676
+ //Blacklist that node
677
+ this.intermediaryDiscovery.removeIntermediary(data.intermediary);
678
+ swapLimitsChanged = true;
679
+ } else if(e instanceof OutOfBoundsError) {
680
+ if(min==null || max==null) {
681
+ min = e.min;
682
+ max = e.max;
683
+ } else {
684
+ min = bigIntMin(min, e.min);
685
+ max = bigIntMax(max, e.max);
686
+ }
687
+ data.intermediary.swapBounds[swapType] ??= {};
688
+ data.intermediary.swapBounds[swapType]![chainIdentifier] ??= {};
689
+ const tokenBoundsData = (data.intermediary.swapBounds[swapType]![chainIdentifier]![amountData.token] ??= {input: {}, output: {}});
690
+ if(amountData.exactIn) {
691
+ tokenBoundsData.input = {min: e.min, max: e.max};
692
+ } else {
693
+ tokenBoundsData.output = {min: e.min, max: e.max};
694
+ }
695
+ swapLimitsChanged = true;
696
+ }
697
+ this.logger.warn("createSwap(): Intermediary "+data.intermediary.url+" error: ", e);
698
+ error = e;
699
+
700
+ if(numResolved===quotePromises.length) {
701
+ if(timeout!=null) clearTimeout(timeout);
702
+ if(quotes.length>0) {
703
+ resolve(quotes);
704
+ return;
705
+ }
706
+ if(min!=null && max!=null) {
707
+ reject(new OutOfBoundsError("Out of bounds", 400, min, max));
708
+ return;
709
+ }
710
+ reject(error);
711
+ }
712
+ });
713
+ });
714
+ });
715
+
716
+ try {
717
+ const quotes = await promiseAll;
718
+
719
+ //TODO: Intermediary's reputation is not taken into account!
720
+ quotes.sort((a, b) => {
721
+ if(amountData.exactIn) {
722
+ //Compare outputs
723
+ return bigIntCompare(b.quote.getOutput()!.rawAmount, a.quote.getOutput()!.rawAmount);
724
+ } else {
725
+ //Compare inputs
726
+ return bigIntCompare(a.quote.getInput()!.rawAmount, b.quote.getInput()!.rawAmount);
727
+ }
728
+ });
729
+
730
+ this.logger.debug("createSwap(): Sorted quotes, best price to worst: ", quotes);
731
+
732
+ if(swapLimitsChanged) this.emit("swapLimitsChanged");
733
+
734
+ const quote = quotes[0].quote;
735
+ if(this.options.saveUninitializedSwaps) {
736
+ quote._setInitiated();
737
+ await quote._save();
738
+ }
739
+ return quote;
740
+ } catch (e) {
741
+ if(swapLimitsChanged) this.emit("swapLimitsChanged");
742
+ throw e;
743
+ }
744
+ }
745
+
746
+ /**
747
+ * Creates To BTC swap
748
+ *
749
+ * @param chainIdentifier
750
+ * @param signer
751
+ * @param tokenAddress Token address to pay with
752
+ * @param address Recipient's bitcoin address
753
+ * @param amount Amount to send in satoshis (bitcoin's smallest denomination)
754
+ * @param exactIn Whether to use exact in instead of exact out
755
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
756
+ * @param options
757
+ */
758
+ createToBTCSwap<ChainIdentifier extends ChainIds<T>>(
759
+ chainIdentifier: ChainIdentifier,
760
+ signer: string,
761
+ tokenAddress: string,
762
+ address: string,
763
+ amount: bigint,
764
+ exactIn: boolean = false,
765
+ additionalParams: Record<string, any> | undefined = this.options.defaultAdditionalParameters,
766
+ options?: ToBTCOptions
767
+ ): Promise<ToBTCSwap<T[ChainIdentifier]>> {
768
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
769
+ if(address.startsWith("bitcoin:")) {
770
+ address = address.substring(8).split("?")[0];
771
+ }
772
+ if(!this.Utils.isValidBitcoinAddress(address)) throw new Error("Invalid bitcoin address");
773
+ if(!this.chains[chainIdentifier].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainIdentifier+" address");
774
+ signer = this.chains[chainIdentifier].chainInterface.normalizeAddress(signer);
775
+ options ??= {};
776
+ options.confirmationTarget ??= 3;
777
+ options.confirmations ??= 2;
778
+ const amountData = {
779
+ amount,
780
+ token: tokenAddress,
781
+ exactIn
782
+ };
783
+ return this.createSwap(
784
+ chainIdentifier as ChainIdentifier,
785
+ (candidates: Intermediary[], abortSignal, chain) => Promise.resolve(chain.wrappers[SwapType.TO_BTC].create(
786
+ signer,
787
+ address,
788
+ amountData,
789
+ candidates,
790
+ options,
791
+ additionalParams,
792
+ abortSignal
793
+ )),
794
+ amountData,
795
+ SwapType.TO_BTC
796
+ );
797
+ }
798
+
799
+ /**
800
+ * Creates To BTCLN swap
801
+ *
802
+ * @param chainIdentifier
803
+ * @param signer
804
+ * @param tokenAddress Token address to pay with
805
+ * @param paymentRequest BOLT11 lightning network invoice to be paid (needs to have a fixed amount)
806
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
807
+ * @param options
808
+ */
809
+ async createToBTCLNSwap<ChainIdentifier extends ChainIds<T>>(
810
+ chainIdentifier: ChainIdentifier,
811
+ signer: string,
812
+ tokenAddress: string,
813
+ paymentRequest: string,
814
+ additionalParams: Record<string, any> | undefined = this.options.defaultAdditionalParameters,
815
+ options?: ToBTCLNOptions
816
+ ): Promise<ToBTCLNSwap<T[ChainIdentifier]>> {
817
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
818
+ options ??= {};
819
+ if(paymentRequest.startsWith("lightning:")) paymentRequest = paymentRequest.substring(10);
820
+ if(!this.Utils.isValidLightningInvoice(paymentRequest)) throw new Error("Invalid lightning network invoice");
821
+ if(!this.chains[chainIdentifier].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainIdentifier+" address");
822
+ signer = this.chains[chainIdentifier].chainInterface.normalizeAddress(signer);
823
+ const parsedPR = bolt11Decode(paymentRequest);
824
+ if(parsedPR.millisatoshis==null) throw new Error("Invalid lightning network invoice, no msat value field!");
825
+ const amountData = {
826
+ amount: (BigInt(parsedPR.millisatoshis) + 999n) / 1000n,
827
+ token: tokenAddress,
828
+ exactIn: false
829
+ };
830
+ options.expirySeconds ??= 5*24*3600;
831
+ return this.createSwap(
832
+ chainIdentifier as ChainIdentifier,
833
+ (candidates: Intermediary[], abortSignal: AbortSignal, chain) => chain.wrappers[SwapType.TO_BTCLN].create(
834
+ signer,
835
+ paymentRequest,
836
+ amountData,
837
+ candidates,
838
+ options,
839
+ additionalParams,
840
+ abortSignal
841
+ ),
842
+ amountData,
843
+ SwapType.TO_BTCLN
844
+ );
845
+ }
846
+
847
+ /**
848
+ * Creates To BTCLN swap via LNURL-pay
849
+ *
850
+ * @param chainIdentifier
851
+ * @param signer
852
+ * @param tokenAddress Token address to pay with
853
+ * @param lnurlPay LNURL-pay link to use for the payment
854
+ * @param amount Amount to be paid in sats
855
+ * @param exactIn Whether to do an exact in swap instead of exact out
856
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
857
+ * @param options
858
+ */
859
+ async createToBTCLNSwapViaLNURL<ChainIdentifier extends ChainIds<T>>(
860
+ chainIdentifier: ChainIdentifier,
861
+ signer: string,
862
+ tokenAddress: string,
863
+ lnurlPay: string | LNURLPay,
864
+ amount: bigint,
865
+ exactIn: boolean = false,
866
+ additionalParams: Record<string, any> | undefined = this.options.defaultAdditionalParameters,
867
+ options?: ToBTCLNOptions & {comment?: string}
868
+ ): Promise<ToBTCLNSwap<T[ChainIdentifier]>> {
869
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
870
+ if(typeof(lnurlPay)==="string" && !this.Utils.isValidLNURL(lnurlPay)) throw new Error("Invalid LNURL-pay link");
871
+ if(!this.chains[chainIdentifier].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainIdentifier+" address");
872
+ signer = this.chains[chainIdentifier].chainInterface.normalizeAddress(signer);
873
+ const amountData = {
874
+ amount,
875
+ token: tokenAddress,
876
+ exactIn
877
+ };
878
+ options ??= {};
879
+ options.expirySeconds ??= 5*24*3600;
880
+ return this.createSwap(
881
+ chainIdentifier as ChainIdentifier,
882
+ (candidates: Intermediary[], abortSignal: AbortSignal, chain) => chain.wrappers[SwapType.TO_BTCLN].createViaLNURL(
883
+ signer,
884
+ typeof(lnurlPay)==="string" ? (lnurlPay.startsWith("lightning:") ? lnurlPay.substring(10): lnurlPay) : lnurlPay.params,
885
+ amountData,
886
+ candidates,
887
+ options,
888
+ additionalParams,
889
+ abortSignal
890
+ ),
891
+ amountData,
892
+ SwapType.TO_BTCLN
893
+ );
894
+ }
895
+
896
+ /**
897
+ * Creates To BTCLN swap via InvoiceCreationService
898
+ *
899
+ * @param chainIdentifier
900
+ * @param signer
901
+ * @param tokenAddress Token address to pay with
902
+ * @param service Invoice create service object which facilitates the creation of fixed amount LN invoices
903
+ * @param amount Amount to be paid in sats
904
+ * @param exactIn Whether to do an exact in swap instead of exact out
905
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
906
+ * @param options
907
+ */
908
+ async createToBTCLNSwapViaInvoiceCreateService<ChainIdentifier extends ChainIds<T>>(
909
+ chainIdentifier: ChainIdentifier,
910
+ signer: string,
911
+ tokenAddress: string,
912
+ service: InvoiceCreateService,
913
+ amount: bigint,
914
+ exactIn: boolean = false,
915
+ additionalParams: Record<string, any> | undefined = this.options.defaultAdditionalParameters,
916
+ options?: ToBTCLNOptions
917
+ ): Promise<ToBTCLNSwap<T[ChainIdentifier]>> {
918
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
919
+ if(!this.chains[chainIdentifier].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainIdentifier+" address");
920
+ signer = this.chains[chainIdentifier].chainInterface.normalizeAddress(signer);
921
+ options ??= {};
922
+ const amountData = {
923
+ amount,
924
+ token: tokenAddress,
925
+ exactIn
926
+ };
927
+ options.expirySeconds ??= 5*24*3600;
928
+ return this.createSwap(
929
+ chainIdentifier as ChainIdentifier,
930
+ (candidates: Intermediary[], abortSignal: AbortSignal, chain) => chain.wrappers[SwapType.TO_BTCLN].createViaInvoiceCreateService(
931
+ signer,
932
+ Promise.resolve(service),
933
+ amountData,
934
+ candidates,
935
+ options,
936
+ additionalParams,
937
+ abortSignal
938
+ ),
939
+ amountData,
940
+ SwapType.TO_BTCLN
941
+ );
942
+ }
943
+
944
+ /**
945
+ * Creates From BTC swap
946
+ *
947
+ * @param chainIdentifier
948
+ * @param signer
949
+ * @param tokenAddress Token address to receive
950
+ * @param amount Amount to receive, in satoshis (bitcoin's smallest denomination)
951
+ * @param exactOut Whether to use a exact out instead of exact in
952
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
953
+ * @param options
954
+ */
955
+ async createFromBTCSwapNew<ChainIdentifier extends ChainIds<T>>(
956
+ chainIdentifier: ChainIdentifier,
957
+ signer: string,
958
+ tokenAddress: string,
959
+ amount: bigint,
960
+ exactOut: boolean = false,
961
+ additionalParams: Record<string, any> | undefined = this.options.defaultAdditionalParameters,
962
+ options?: SpvFromBTCOptions
963
+ ): Promise<SpvFromBTCSwap<T[ChainIdentifier]>> {
964
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
965
+ if(!this.chains[chainIdentifier].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainIdentifier+" address");
966
+ signer = this.chains[chainIdentifier].chainInterface.normalizeAddress(signer);
967
+ const amountData = {
968
+ amount,
969
+ token: tokenAddress,
970
+ exactIn: !exactOut
971
+ };
972
+ return this.createSwap(
973
+ chainIdentifier as ChainIdentifier,
974
+ (candidates: Intermediary[], abortSignal: AbortSignal, chain) => Promise.resolve(chain.wrappers[SwapType.SPV_VAULT_FROM_BTC].create(
975
+ signer,
976
+ amountData,
977
+ candidates,
978
+ options,
979
+ additionalParams,
980
+ abortSignal
981
+ )),
982
+ amountData,
983
+ SwapType.SPV_VAULT_FROM_BTC
984
+ );
985
+ }
986
+
987
+ /**
988
+ * Creates From BTC swap
989
+ *
990
+ * @param chainIdentifier
991
+ * @param signer
992
+ * @param tokenAddress Token address to receive
993
+ * @param amount Amount to receive, in satoshis (bitcoin's smallest denomination)
994
+ * @param exactOut Whether to use a exact out instead of exact in
995
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
996
+ * @param options
997
+ */
998
+ async createFromBTCSwap<ChainIdentifier extends ChainIds<T>>(
999
+ chainIdentifier: ChainIdentifier,
1000
+ signer: string,
1001
+ tokenAddress: string,
1002
+ amount: bigint,
1003
+ exactOut: boolean = false,
1004
+ additionalParams: Record<string, any> | undefined = this.options.defaultAdditionalParameters,
1005
+ options?: FromBTCOptions
1006
+ ): Promise<FromBTCSwap<T[ChainIdentifier]>> {
1007
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
1008
+ if(!this.chains[chainIdentifier].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainIdentifier+" address");
1009
+ signer = this.chains[chainIdentifier].chainInterface.normalizeAddress(signer);
1010
+ const amountData = {
1011
+ amount,
1012
+ token: tokenAddress,
1013
+ exactIn: !exactOut
1014
+ };
1015
+ return this.createSwap(
1016
+ chainIdentifier as ChainIdentifier,
1017
+ (candidates: Intermediary[], abortSignal: AbortSignal, chain) => Promise.resolve(chain.wrappers[SwapType.FROM_BTC].create(
1018
+ signer,
1019
+ amountData,
1020
+ candidates,
1021
+ options,
1022
+ additionalParams,
1023
+ abortSignal
1024
+ )),
1025
+ amountData,
1026
+ SwapType.FROM_BTC
1027
+ );
1028
+ }
1029
+
1030
+ /**
1031
+ * Creates From BTCLN swap
1032
+ *
1033
+ * @param chainIdentifier
1034
+ * @param signer
1035
+ * @param tokenAddress Token address to receive
1036
+ * @param amount Amount to receive, in satoshis (bitcoin's smallest denomination)
1037
+ * @param exactOut Whether to use exact out instead of exact in
1038
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
1039
+ * @param options
1040
+ */
1041
+ async createFromBTCLNSwap<ChainIdentifier extends ChainIds<T>>(
1042
+ chainIdentifier: ChainIdentifier,
1043
+ signer: string,
1044
+ tokenAddress: string,
1045
+ amount: bigint,
1046
+ exactOut: boolean = false,
1047
+ additionalParams: Record<string, any> | undefined = this.options.defaultAdditionalParameters,
1048
+ options?: FromBTCLNOptions
1049
+ ): Promise<FromBTCLNSwap<T[ChainIdentifier]>> {
1050
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
1051
+ if(!this.chains[chainIdentifier].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainIdentifier+" address");
1052
+ signer = this.chains[chainIdentifier].chainInterface.normalizeAddress(signer);
1053
+ const amountData = {
1054
+ amount,
1055
+ token: tokenAddress,
1056
+ exactIn: !exactOut
1057
+ };
1058
+ return this.createSwap(
1059
+ chainIdentifier as ChainIdentifier,
1060
+ (candidates: Intermediary[], abortSignal: AbortSignal, chain) => Promise.resolve(chain.wrappers[SwapType.FROM_BTCLN].create(
1061
+ signer,
1062
+ amountData,
1063
+ candidates,
1064
+ options,
1065
+ additionalParams,
1066
+ abortSignal
1067
+ )),
1068
+ amountData,
1069
+ SwapType.FROM_BTCLN
1070
+ );
1071
+ }
1072
+
1073
+ /**
1074
+ * Creates From BTCLN swap, withdrawing from LNURL-withdraw
1075
+ *
1076
+ * @param chainIdentifier
1077
+ * @param signer
1078
+ * @param tokenAddress Token address to receive
1079
+ * @param lnurl LNURL-withdraw to pull the funds from
1080
+ * @param amount Amount to receive, in satoshis (bitcoin's smallest denomination)
1081
+ * @param exactOut Whether to use exact out instead of exact in
1082
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
1083
+ */
1084
+ async createFromBTCLNSwapViaLNURL<ChainIdentifier extends ChainIds<T>>(
1085
+ chainIdentifier: ChainIdentifier,
1086
+ signer: string,
1087
+ tokenAddress: string,
1088
+ lnurl: string | LNURLWithdraw,
1089
+ amount: bigint,
1090
+ exactOut: boolean = false,
1091
+ additionalParams: Record<string, any> | undefined = this.options.defaultAdditionalParameters
1092
+ ): Promise<FromBTCLNSwap<T[ChainIdentifier]>> {
1093
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
1094
+ if(typeof(lnurl)==="string" && !this.Utils.isValidLNURL(lnurl)) throw new Error("Invalid LNURL-withdraw link");
1095
+ if(!this.chains[chainIdentifier].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainIdentifier+" address");
1096
+ signer = this.chains[chainIdentifier].chainInterface.normalizeAddress(signer);
1097
+ const amountData = {
1098
+ amount,
1099
+ token: tokenAddress,
1100
+ exactIn: !exactOut
1101
+ };
1102
+ return this.createSwap(
1103
+ chainIdentifier as ChainIdentifier,
1104
+ (candidates: Intermediary[], abortSignal: AbortSignal, chain) => chain.wrappers[SwapType.FROM_BTCLN].createViaLNURL(
1105
+ signer,
1106
+ typeof(lnurl)==="string" ? (lnurl.startsWith("lightning:") ? lnurl.substring(10): lnurl) : lnurl.params,
1107
+ amountData,
1108
+ candidates,
1109
+ additionalParams,
1110
+ abortSignal
1111
+ ),
1112
+ amountData,
1113
+ SwapType.FROM_BTCLN
1114
+ );
1115
+ }
1116
+
1117
+ /**
1118
+ * Creates From BTCLN swap using new protocol
1119
+ *
1120
+ * @param chainIdentifier
1121
+ * @param signer
1122
+ * @param tokenAddress Token address to receive
1123
+ * @param amount Amount to receive, in satoshis (bitcoin's smallest denomination)
1124
+ * @param exactOut Whether to use exact out instead of exact in
1125
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
1126
+ * @param options
1127
+ */
1128
+ async createFromBTCLNSwapNew<ChainIdentifier extends ChainIds<T>>(
1129
+ chainIdentifier: ChainIdentifier,
1130
+ signer: string,
1131
+ tokenAddress: string,
1132
+ amount: bigint,
1133
+ exactOut: boolean = false,
1134
+ additionalParams: Record<string, any> | undefined = this.options.defaultAdditionalParameters,
1135
+ options?: FromBTCLNAutoOptions
1136
+ ): Promise<FromBTCLNAutoSwap<T[ChainIdentifier]>> {
1137
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
1138
+ if(!this.chains[chainIdentifier].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainIdentifier+" address");
1139
+ signer = this.chains[chainIdentifier].chainInterface.normalizeAddress(signer);
1140
+ const amountData = {
1141
+ amount,
1142
+ token: tokenAddress,
1143
+ exactIn: !exactOut
1144
+ };
1145
+ return this.createSwap(
1146
+ chainIdentifier as ChainIdentifier,
1147
+ (candidates: Intermediary[], abortSignal: AbortSignal, chain) => Promise.resolve(chain.wrappers[SwapType.FROM_BTCLN_AUTO].create(
1148
+ signer,
1149
+ amountData,
1150
+ candidates,
1151
+ options,
1152
+ additionalParams,
1153
+ abortSignal
1154
+ )),
1155
+ amountData,
1156
+ SwapType.FROM_BTCLN_AUTO
1157
+ );
1158
+ }
1159
+
1160
+ /**
1161
+ * Creates From BTCLN swap using new protocol, withdrawing from LNURL-withdraw
1162
+ *
1163
+ * @param chainIdentifier
1164
+ * @param signer
1165
+ * @param tokenAddress Token address to receive
1166
+ * @param lnurl LNURL-withdraw to pull the funds from
1167
+ * @param amount Amount to receive, in satoshis (bitcoin's smallest denomination)
1168
+ * @param exactOut Whether to use exact out instead of exact in
1169
+ * @param additionalParams Additional parameters sent to the LP when creating the swap
1170
+ * @param options
1171
+ */
1172
+ async createFromBTCLNSwapNewViaLNURL<ChainIdentifier extends ChainIds<T>>(
1173
+ chainIdentifier: ChainIdentifier,
1174
+ signer: string,
1175
+ tokenAddress: string,
1176
+ lnurl: string | LNURLWithdraw,
1177
+ amount: bigint,
1178
+ exactOut: boolean = false,
1179
+ additionalParams: Record<string, any> | undefined = this.options.defaultAdditionalParameters,
1180
+ options?: FromBTCLNAutoOptions
1181
+ ): Promise<FromBTCLNAutoSwap<T[ChainIdentifier]>> {
1182
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
1183
+ if(typeof(lnurl)==="string" && !this.Utils.isValidLNURL(lnurl)) throw new Error("Invalid LNURL-withdraw link");
1184
+ if(!this.chains[chainIdentifier].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainIdentifier+" address");
1185
+ signer = this.chains[chainIdentifier].chainInterface.normalizeAddress(signer);
1186
+ const amountData = {
1187
+ amount,
1188
+ token: tokenAddress,
1189
+ exactIn: !exactOut
1190
+ };
1191
+ return this.createSwap(
1192
+ chainIdentifier as ChainIdentifier,
1193
+ (candidates: Intermediary[], abortSignal: AbortSignal, chain) => chain.wrappers[SwapType.FROM_BTCLN_AUTO].createViaLNURL(
1194
+ signer,
1195
+ typeof(lnurl)==="string" ? (lnurl.startsWith("lightning:") ? lnurl.substring(10): lnurl) : lnurl.params,
1196
+ amountData,
1197
+ candidates,
1198
+ options,
1199
+ additionalParams,
1200
+ abortSignal
1201
+ ),
1202
+ amountData,
1203
+ SwapType.FROM_BTCLN_AUTO
1204
+ );
1205
+ }
1206
+
1207
+ /**
1208
+ * Creates trusted LN for Gas swap
1209
+ *
1210
+ * @param chainId
1211
+ * @param signer
1212
+ * @param amount Amount of native token to receive, in base units
1213
+ * @param trustedIntermediaryOrUrl URL or Intermediary object of the trusted intermediary to use, otherwise uses default
1214
+ * @throws {Error} If no trusted intermediary specified
1215
+ */
1216
+ createTrustedLNForGasSwap<C extends ChainIds<T>>(chainId: C, signer: string, amount: bigint, trustedIntermediaryOrUrl?: Intermediary | string): Promise<LnForGasSwap<T[C]>> {
1217
+ if(this.chains[chainId]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainId);
1218
+ if(!this.chains[chainId].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainId+" address");
1219
+ signer = this.chains[chainId].chainInterface.normalizeAddress(signer);
1220
+ const useUrl = trustedIntermediaryOrUrl ?? this.defaultTrustedIntermediary ?? this.options.defaultTrustedIntermediaryUrl;
1221
+ if(useUrl==null) throw new Error("No trusted intermediary specified!");
1222
+ return this.chains[chainId as C].wrappers[SwapType.TRUSTED_FROM_BTCLN].create(signer, amount, useUrl);
1223
+ }
1224
+
1225
+ /**
1226
+ * Creates trusted BTC on-chain for Gas swap
1227
+ *
1228
+ * @param chainId
1229
+ * @param signer
1230
+ * @param amount Amount of native token to receive, in base units
1231
+ * @param refundAddress Bitcoin refund address, in case the swap fails
1232
+ * @param trustedIntermediaryOrUrl URL or Intermediary object of the trusted intermediary to use, otherwise uses default
1233
+ * @throws {Error} If no trusted intermediary specified
1234
+ */
1235
+ createTrustedOnchainForGasSwap<C extends ChainIds<T>>(
1236
+ chainId: C, signer: string,
1237
+ amount: bigint, refundAddress?: string,
1238
+ trustedIntermediaryOrUrl?: Intermediary | string
1239
+ ): Promise<OnchainForGasSwap<T[C]>> {
1240
+ if(this.chains[chainId]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainId);
1241
+ if(!this.chains[chainId].chainInterface.isValidAddress(signer, true)) throw new Error("Invalid "+chainId+" address");
1242
+ signer = this.chains[chainId].chainInterface.normalizeAddress(signer);
1243
+ const useUrl = trustedIntermediaryOrUrl ?? this.defaultTrustedIntermediary ?? this.options.defaultTrustedIntermediaryUrl;
1244
+ if(useUrl==null) throw new Error("No trusted intermediary specified!");
1245
+ return this.chains[chainId as C].wrappers[SwapType.TRUSTED_FROM_BTC].create(signer, amount, useUrl, refundAddress);
1246
+ }
1247
+
1248
+ create<C extends ChainIds<T>>(signer: string, srcToken: BtcToken<true>, dstToken: SCToken<C>, amount: bigint, exactIn: boolean, lnurlWithdraw?: string | LNURLWithdraw): Promise<(SupportsSwapType<T[C], SwapType.FROM_BTCLN_AUTO> extends true ? FromBTCLNAutoSwap<T[C]> : FromBTCLNSwap<T[C]>)>;
1249
+ create<C extends ChainIds<T>>(signer: string, srcToken: BtcToken<false>, dstToken: SCToken<C>, amount: bigint, exactIn: boolean): Promise<(SupportsSwapType<T[C], SwapType.SPV_VAULT_FROM_BTC> extends true ? SpvFromBTCSwap<T[C]> : FromBTCSwap<T[C]>)>;
1250
+ create<C extends ChainIds<T>>(signer: string, srcToken: SCToken<C>, dstToken: BtcToken<false>, amount: bigint, exactIn: boolean, address: string): Promise<ToBTCSwap<T[C]>>;
1251
+ create<C extends ChainIds<T>>(signer: string, srcToken: SCToken<C>, dstToken: BtcToken<true>, amount: bigint, exactIn: boolean, lnurlPay: string | LNURLPay): Promise<ToBTCLNSwap<T[C]>>;
1252
+ create<C extends ChainIds<T>>(signer: string, srcToken: SCToken<C>, dstToken: BtcToken<true>, amount: bigint, exactIn: false, lightningInvoice: string): Promise<ToBTCLNSwap<T[C]>>;
1253
+ create<C extends ChainIds<T>>(signer: string, srcToken: Token<C>, dstToken: Token<C>, amount: bigint, exactIn: boolean, addressLnurlLightningInvoice?: string | LNURLWithdraw | LNURLPay): Promise<ISwap<T[C]>>;
1254
+ /**
1255
+ * Creates a swap from srcToken to dstToken, of a specific token amount, either specifying input amount (exactIn=true)
1256
+ * or output amount (exactIn=false), NOTE: For regular -> BTC-LN (lightning) swaps the passed amount is ignored and
1257
+ * invoice's pre-set amount is used instead.
1258
+ * @deprecated Use swap() instead
1259
+ *
1260
+ * @param signer Smartchain (Solana, Starknet, etc.) address of the user
1261
+ * @param srcToken Source token of the swap, user pays this token
1262
+ * @param dstToken Destination token of the swap, user receives this token
1263
+ * @param amount Amount of the swap
1264
+ * @param exactIn Whether the amount specified is an input amount (exactIn=true) or an output amount (exactIn=false)
1265
+ * @param addressLnurlLightningInvoice Bitcoin on-chain address, lightning invoice, LNURL-pay to pay or
1266
+ * LNURL-withdrawal to withdraw money from
1267
+ */
1268
+ create<C extends ChainIds<T>>(signer: string, srcToken: Token<C>, dstToken: Token<C>, amount: bigint, exactIn: boolean, addressLnurlLightningInvoice?: string | LNURLWithdraw | LNURLPay): Promise<ISwap<T[C]>> {
1269
+ if(srcToken.chain==="BTC") {
1270
+ return this.swap(srcToken, dstToken, amount, exactIn, addressLnurlLightningInvoice as any, signer);
1271
+ } else {
1272
+ return this.swap(srcToken, dstToken, amount, exactIn, signer, addressLnurlLightningInvoice as any);
1273
+ }
1274
+ }
1275
+
1276
+ swap<C extends ChainIds<T>>(srcToken: BtcToken<true>, dstToken: SCToken<C>, amount: bigint | string, exactIn: boolean | SwapAmountType, src: undefined | string | LNURLWithdraw, dstSmartchainWallet: string, options?: (SupportsSwapType<T[C], SwapType.FROM_BTCLN_AUTO> extends true ? FromBTCLNAutoOptions : FromBTCLNOptions)): Promise<(SupportsSwapType<T[C], SwapType.FROM_BTCLN_AUTO> extends true ? FromBTCLNAutoSwap<T[C]> : FromBTCLNSwap<T[C]>)>;
1277
+ swap<C extends ChainIds<T>>(srcToken: BtcToken<false>, dstToken: SCToken<C>, amount: bigint | string, exactIn: boolean | SwapAmountType, src: undefined | string, dstSmartchainWallet: string, options?: (SupportsSwapType<T[C], SwapType.SPV_VAULT_FROM_BTC> extends true ? SpvFromBTCOptions : FromBTCOptions)): Promise<(SupportsSwapType<T[C], SwapType.SPV_VAULT_FROM_BTC> extends true ? SpvFromBTCSwap<T[C]> : FromBTCSwap<T[C]>)>;
1278
+ swap<C extends ChainIds<T>>(srcToken: SCToken<C>, dstToken: BtcToken<false>, amount: bigint | string, exactIn: boolean | SwapAmountType, src: string, dstAddress: string, options?: ToBTCOptions): Promise<ToBTCSwap<T[C]>>;
1279
+ swap<C extends ChainIds<T>>(srcToken: SCToken<C>, dstToken: BtcToken<true>, amount: bigint | string, exactIn: boolean | SwapAmountType, src: string, dstLnurlPayOrInvoiceCreateService: string | LNURLPay | InvoiceCreateService, options?: ToBTCLNOptions & {comment?: string}): Promise<ToBTCLNSwap<T[C]>>;
1280
+ swap<C extends ChainIds<T>>(srcToken: SCToken<C>, dstToken: BtcToken<true>, amount: bigint | string, exactIn: false | SwapAmountType.EXACT_OUT, src: string, dstLightningInvoice: string, options?: ToBTCLNOptions): Promise<ToBTCLNSwap<T[C]>>;
1281
+ swap<C extends ChainIds<T>>(srcToken: Token<C> | string, dstToken: Token<C> | string, amount: bigint | string, exactIn: boolean | SwapAmountType, src: undefined | string | LNURLWithdraw, dst: string | LNURLPay | InvoiceCreateService, options?: FromBTCLNOptions | SpvFromBTCOptions | FromBTCOptions | ToBTCOptions | (ToBTCLNOptions & {comment?: string}) | FromBTCLNAutoOptions): Promise<ISwap<T[C]>>;
1282
+ /**
1283
+ * Creates a swap from srcToken to dstToken, of a specific token amount, either specifying input amount (exactIn=true)
1284
+ * or output amount (exactIn=false), NOTE: For regular SmartChain -> BTC-LN (lightning) swaps the passed amount is ignored and
1285
+ * invoice's pre-set amount is used instead, use LNURL-pay for dynamic amounts
1286
+ *
1287
+ * @param _srcToken Source token of the swap, user pays this token
1288
+ * @param _dstToken Destination token of the swap, user receives this token
1289
+ * @param _amount Amount of the swap either in base units as {bigint} or in human readable format (with decimals) as {string}
1290
+ * @param exactIn Whether the amount specified is an input amount (exactIn=true) or an output amount (exactIn=false)
1291
+ * @param src Source wallet/lnurl-withdraw of the swap
1292
+ * @param dst Destination smart chain address, bitcoin on-chain address, lightning invoice, LNURL-pay
1293
+ * @param options Options for the swap
1294
+ */
1295
+ swap<C extends ChainIds<T>>(
1296
+ _srcToken: Token<C> | string,
1297
+ _dstToken: Token<C> | string,
1298
+ _amount: bigint | string,
1299
+ exactIn: boolean | SwapAmountType,
1300
+ src: undefined | string | LNURLWithdraw,
1301
+ dst: string | LNURLPay | InvoiceCreateService,
1302
+ options?: FromBTCLNOptions | SpvFromBTCOptions | FromBTCOptions | ToBTCOptions | (ToBTCLNOptions & {comment?: string}) | FromBTCLNAutoOptions
1303
+ ): Promise<ISwap<T[C]>> {
1304
+ const srcToken = typeof(_srcToken)==="string" ? this.getToken(_srcToken) as Token<C> : _srcToken;
1305
+ const dstToken = typeof(_dstToken)==="string" ? this.getToken(_dstToken) as Token<C> : _dstToken;
1306
+ const amount = _amount==null ? null : (typeof(_amount)==="bigint" ? _amount : fromDecimal(_amount, exactIn ? srcToken.decimals : dstToken.decimals));
1307
+ if(srcToken.chain==="BTC") {
1308
+ if(dstToken.chain==="SC") {
1309
+ if(typeof(dst)!=="string") throw new Error("Destination for BTC/BTC-LN -> smart chain swaps must be a smart chain address!");
1310
+ if(amount==null) throw new Error("Amount cannot be null for from btc swaps!");
1311
+ if(srcToken.lightning) {
1312
+ //FROM_BTCLN
1313
+ if(src!=null) {
1314
+ if(typeof(src)!=="string" && !isLNURLWithdraw(src)) throw new Error("LNURL must be a string or LNURLWithdraw object!");
1315
+ return this.supportsSwapType(dstToken.chainId, SwapType.FROM_BTCLN_AUTO) ?
1316
+ this.createFromBTCLNSwapNewViaLNURL(dstToken.chainId, dst, dstToken.address, src, amount, !exactIn, undefined, options as any) :
1317
+ this.createFromBTCLNSwapViaLNURL(dstToken.chainId, dst, dstToken.address, src, amount, !exactIn);
1318
+ } else {
1319
+ return this.supportsSwapType(dstToken.chainId, SwapType.FROM_BTCLN_AUTO) ?
1320
+ this.createFromBTCLNSwapNew(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options as any):
1321
+ this.createFromBTCLNSwap(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options as any);
1322
+ }
1323
+ } else {
1324
+ //FROM_BTC
1325
+ if(this.supportsSwapType(dstToken.chainId, SwapType.SPV_VAULT_FROM_BTC)) {
1326
+ return this.createFromBTCSwapNew(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options as any);
1327
+ } else {
1328
+ return this.createFromBTCSwap(dstToken.chainId, dst, dstToken.address, amount, !exactIn, undefined, options as any);
1329
+ }
1330
+ }
1331
+ }
1332
+ } else {
1333
+ if(dstToken.chain==="BTC") {
1334
+ if(typeof(src)!=="string") throw new Error("Source address for BTC/BTC-LN -> smart chain swaps must be a smart chain address!");
1335
+ if(dstToken.lightning) {
1336
+ //TO_BTCLN
1337
+ if(typeof(dst)!=="string" && !isLNURLPay(dst)) throw new Error("Destination LNURL link/lightning invoice must be a string or LNURLPay object!");
1338
+ if(isLNURLPay(dst) || this.Utils.isValidLNURL(dst)) {
1339
+ if(amount==null) throw new Error("Amount cannot be null for to btcln swaps via LNURL-pay!");
1340
+ return this.createToBTCLNSwapViaLNURL(srcToken.chainId, src, srcToken.address, dst, amount, !!exactIn, undefined, options as any);
1341
+ } else if(isInvoiceCreateService(dst)) {
1342
+ if(amount==null) throw new Error("Amount cannot be null for to btcln swaps via InvoiceCreateService!");
1343
+ return this.createToBTCLNSwapViaInvoiceCreateService(srcToken.chainId, src, srcToken.address, dst, amount, !!exactIn, undefined, options as any);
1344
+ } else if(this.Utils.isLightningInvoice(dst)) {
1345
+ if(!this.Utils.isValidLightningInvoice(dst))
1346
+ throw new Error("Invalid lightning invoice specified, lightning invoice MUST contain pre-set amount!");
1347
+ if(exactIn)
1348
+ throw new Error("Only exact out swaps are possible with lightning invoices, use LNURL links for exact in lightning swaps!");
1349
+ return this.createToBTCLNSwap(srcToken.chainId, src, srcToken.address, dst, undefined, options as any);
1350
+ } else {
1351
+ throw new Error("Supplied parameter is not LNURL link nor lightning invoice (bolt11)!");
1352
+ }
1353
+ } else {
1354
+ //TO_BTC
1355
+ if(typeof(dst)!=="string") throw new Error("Destination bitcoin address must be a string!");
1356
+ if(amount==null) throw new Error("Amount cannot be null for to btc swaps!");
1357
+ return this.createToBTCSwap(srcToken.chainId, src, srcToken.address, dst, amount, !!exactIn, undefined, options as any);
1358
+ }
1359
+ }
1360
+ }
1361
+ throw new Error("Unsupported swap type");
1362
+ }
1363
+
1364
+ /**
1365
+ * Returns all swaps
1366
+ */
1367
+ getAllSwaps(): Promise<ISwap[]>;
1368
+ /**
1369
+ * Returns all swaps for the specific chain, and optionally also for a specific signer's address
1370
+ */
1371
+ getAllSwaps<C extends ChainIds<T>>(chainId: C, signer?: string): Promise<ISwap<T[C]>[]>;
1372
+ async getAllSwaps<C extends ChainIds<T>>(chainId?: C, signer?: string): Promise<ISwap[]> {
1373
+ const queryParams: QueryParams[] = [];
1374
+ if(signer!=null) queryParams.push({key: "initiator", value: signer});
1375
+
1376
+ if(chainId==null) {
1377
+ const res: ISwap[][] = await Promise.all(Object.keys(this.chains).map((chainId) => {
1378
+ const {unifiedSwapStorage, reviver} = this.chains[chainId];
1379
+ return unifiedSwapStorage.query([queryParams], reviver);
1380
+ }));
1381
+ return res.flat();
1382
+ } else {
1383
+ const {unifiedSwapStorage, reviver} = this.chains[chainId];
1384
+ return await unifiedSwapStorage.query([queryParams], reviver);
1385
+ }
1386
+ }
1387
+
1388
+ /**
1389
+ * Returns all swaps where an action is required (either claim or refund)
1390
+ */
1391
+ getActionableSwaps(): Promise<ISwap[]>;
1392
+ /**
1393
+ * Returns swaps where an action is required (either claim or refund) for the specific chain, and optionally also for a specific signer's address
1394
+ */
1395
+ getActionableSwaps<C extends ChainIds<T>>(chainId: C, signer?: string): Promise<ISwap<T[C]>[]>;
1396
+ async getActionableSwaps<C extends ChainIds<T>>(chainId?: C, signer?: string): Promise<ISwap[]> {
1397
+ if(chainId==null) {
1398
+ const res: ISwap[][] = await Promise.all(Object.keys(this.chains).map((chainId) => {
1399
+ const {unifiedSwapStorage, reviver, wrappers} = this.chains[chainId];
1400
+ const queryParams: Array<QueryParams[]> = [];
1401
+ for(let key in wrappers) {
1402
+ const wrapper = wrappers[key as unknown as SwapType];
1403
+ const swapTypeQueryParams: QueryParams[] = [{key: "type", value: wrapper.TYPE}];
1404
+ if(signer!=null) swapTypeQueryParams.push({key: "initiator", value: signer});
1405
+ swapTypeQueryParams.push({key: "state", value: wrapper.pendingSwapStates});
1406
+ queryParams.push(swapTypeQueryParams);
1407
+ }
1408
+ return unifiedSwapStorage.query(queryParams, reviver);
1409
+ }));
1410
+ return res.flat().filter(swap => swap.requiresAction());
1411
+ } else {
1412
+ const {unifiedSwapStorage, reviver, wrappers} = this.chains[chainId];
1413
+ const queryParams: Array<QueryParams[]> = [];
1414
+ for(let key in wrappers) {
1415
+ const wrapper = wrappers[key as unknown as SwapType];
1416
+ const swapTypeQueryParams: QueryParams[] = [{key: "type", value: wrapper.TYPE}];
1417
+ if(signer!=null) swapTypeQueryParams.push({key: "initiator", value: signer});
1418
+ swapTypeQueryParams.push({key: "state", value: wrapper.pendingSwapStates});
1419
+ queryParams.push(swapTypeQueryParams);
1420
+ }
1421
+ return (await unifiedSwapStorage.query(queryParams, reviver)).filter(swap => swap.requiresAction());
1422
+ }
1423
+ }
1424
+
1425
+ /**
1426
+ * Returns all swaps that are refundable
1427
+ */
1428
+ getRefundableSwaps(): Promise<IToBTCSwap[]>;
1429
+ /**
1430
+ * Returns swaps which are refundable for the specific chain, and optionally also for a specific signer's address
1431
+ */
1432
+ getRefundableSwaps<C extends ChainIds<T>>(chainId: C, signer?: string): Promise<IToBTCSwap<T[C]>[]>;
1433
+ async getRefundableSwaps<C extends ChainIds<T>>(chainId?: C, signer?: string): Promise<IToBTCSwap[]> {
1434
+ if(chainId==null) {
1435
+ const res: IToBTCSwap[][] = await Promise.all(Object.keys(this.chains).map((chainId) => {
1436
+ const {unifiedSwapStorage, reviver, wrappers} = this.chains[chainId];
1437
+ const queryParams: Array<QueryParams[]> = [];
1438
+ for(let wrapper of [wrappers[SwapType.TO_BTCLN], wrappers[SwapType.TO_BTC]]) {
1439
+ const swapTypeQueryParams: QueryParams[] = [{key: "type", value: wrapper.TYPE}];
1440
+ if(signer!=null) swapTypeQueryParams.push({key: "initiator", value: signer});
1441
+ swapTypeQueryParams.push({key: "state", value: wrapper.refundableSwapStates});
1442
+ queryParams.push(swapTypeQueryParams);
1443
+ }
1444
+ return unifiedSwapStorage.query<IToBTCSwap<T[C]>>(queryParams, reviver as (val: any) => IToBTCSwap<T[C]>);
1445
+ }));
1446
+ return res.flat().filter(swap => swap.isRefundable());
1447
+ } else {
1448
+ const {unifiedSwapStorage, reviver, wrappers} = this.chains[chainId];
1449
+ const queryParams: Array<QueryParams[]> = [];
1450
+ for(let wrapper of [wrappers[SwapType.TO_BTCLN], wrappers[SwapType.TO_BTC]]) {
1451
+ const swapTypeQueryParams: QueryParams[] = [{key: "type", value: wrapper.TYPE}];
1452
+ if(signer!=null) swapTypeQueryParams.push({key: "initiator", value: signer});
1453
+ swapTypeQueryParams.push({key: "state", value: wrapper.refundableSwapStates});
1454
+ queryParams.push(swapTypeQueryParams);
1455
+ }
1456
+ const result = await unifiedSwapStorage.query<IToBTCSwap<T[C]>>(queryParams, reviver as (val: any) => IToBTCSwap<T[C]>);
1457
+ return result.filter(swap => swap.isRefundable());
1458
+ }
1459
+ }
1460
+
1461
+ /**
1462
+ * Returns all swaps that are manually claimable
1463
+ */
1464
+ getClaimableSwaps(): Promise<IClaimableSwap[]>;
1465
+ /**
1466
+ * Returns all swaps that are manually claimable for the specific chain, and optionally also for a specific signer's address
1467
+ */
1468
+ getClaimableSwaps<C extends ChainIds<T>>(chainId: C, signer?: string): Promise<IClaimableSwap<T[C]>[]>;
1469
+ async getClaimableSwaps<C extends ChainIds<T>>(chainId?: C, signer?: string): Promise<IClaimableSwap[]> {
1470
+ if(chainId==null) {
1471
+ const res: IClaimableSwap[][] = await Promise.all(Object.keys(this.chains).map((chainId) => {
1472
+ const {unifiedSwapStorage, reviver, wrappers} = this.chains[chainId];
1473
+ const queryParams: Array<QueryParams[]> = [];
1474
+ for(let wrapper of [wrappers[SwapType.FROM_BTC], wrappers[SwapType.FROM_BTCLN], wrappers[SwapType.SPV_VAULT_FROM_BTC], wrappers[SwapType.FROM_BTCLN_AUTO]]) {
1475
+ if(wrapper==null) continue;
1476
+ const swapTypeQueryParams: QueryParams[] = [{key: "type", value: wrapper.TYPE}];
1477
+ if(signer!=null) swapTypeQueryParams.push({key: "initiator", value: signer});
1478
+ swapTypeQueryParams.push({key: "state", value: wrapper.claimableSwapStates});
1479
+ queryParams.push(swapTypeQueryParams);
1480
+ }
1481
+ return unifiedSwapStorage.query<IClaimableSwap<T[C]>>(queryParams, reviver as any as (val: any) => IClaimableSwap<T[C]>);
1482
+ }));
1483
+ return res.flat().filter(swap => swap.isClaimable());
1484
+ } else {
1485
+ const {unifiedSwapStorage, reviver, wrappers} = this.chains[chainId];
1486
+ const queryParams: Array<QueryParams[]> = [];
1487
+ for(let wrapper of [wrappers[SwapType.FROM_BTC], wrappers[SwapType.FROM_BTCLN], wrappers[SwapType.SPV_VAULT_FROM_BTC], wrappers[SwapType.FROM_BTCLN_AUTO]]) {
1488
+ if(wrapper==null) continue;
1489
+ const swapTypeQueryParams: QueryParams[] = [{key: "type", value: wrapper.TYPE}];
1490
+ if(signer!=null) swapTypeQueryParams.push({key: "initiator", value: signer});
1491
+ swapTypeQueryParams.push({key: "state", value: wrapper.claimableSwapStates});
1492
+ queryParams.push(swapTypeQueryParams);
1493
+ }
1494
+ const result = await unifiedSwapStorage.query<IClaimableSwap<T[C]>>(queryParams, reviver as any as (val: any) => IClaimableSwap<T[C]>);
1495
+ return result.filter(swap => swap.isClaimable());
1496
+ }
1497
+ }
1498
+
1499
+ /**
1500
+ * Returns swap with a specific id (identifier)
1501
+ */
1502
+ getSwapById(id: string): Promise<ISwap>;
1503
+ /**
1504
+ * Returns swap with a specific id (identifier) on a specific chain and optionally with a signer
1505
+ */
1506
+ getSwapById<C extends ChainIds<T>>(id: string, chainId: C, signer?: string): Promise<ISwap<T[C]>>;
1507
+ async getSwapById<C extends ChainIds<T>>(id: string, chainId?: C, signer?: string): Promise<ISwap> {
1508
+ //Check in pending swaps first
1509
+ if(chainId!=null) {
1510
+ for(let key in this.chains[chainId].wrappers) {
1511
+ const wrapper = this.chains[chainId].wrappers[key as unknown as SwapType];
1512
+ const result = wrapper.pendingSwaps.get(id)?.deref();
1513
+ if(result!=null) {
1514
+ if (signer != null) {
1515
+ if (result._getInitiator() === signer) return result;
1516
+ } else {
1517
+ return result;
1518
+ }
1519
+ }
1520
+ }
1521
+ } else {
1522
+ for(let chainId in this.chains) {
1523
+ for(let key in this.chains[chainId].wrappers) {
1524
+ const wrapper = this.chains[chainId].wrappers[key as unknown as SwapType];
1525
+ const result = wrapper.pendingSwaps.get(id)?.deref();
1526
+ if(result!=null) {
1527
+ if(signer!=null) {
1528
+ if(result._getInitiator()===signer) return result;
1529
+ } else {
1530
+ return result;
1531
+ }
1532
+ }
1533
+ }
1534
+ }
1535
+ }
1536
+
1537
+ const queryParams: QueryParams[] = [];
1538
+ if(signer!=null) queryParams.push({key: "initiator", value: signer});
1539
+ queryParams.push({key: "id", value: id});
1540
+ if(chainId==null) {
1541
+ const res: ISwap[][] = await Promise.all(Object.keys(this.chains).map((chainId) => {
1542
+ const {unifiedSwapStorage, reviver} = this.chains[chainId];
1543
+ return unifiedSwapStorage.query([queryParams], reviver);
1544
+ }));
1545
+ return res.flat()[0];
1546
+ } else {
1547
+ const {unifiedSwapStorage, reviver} = this.chains[chainId];
1548
+ return (await unifiedSwapStorage.query([queryParams], reviver))[0];
1549
+ }
1550
+ }
1551
+
1552
+ /**
1553
+ * Returns the swap with a proper return type, or undefined, if not found, or has wrong type
1554
+ *
1555
+ * @param id
1556
+ * @param chainId
1557
+ * @param swapType
1558
+ * @param signer
1559
+ */
1560
+ async getTypedSwapById<C extends ChainIds<T>, S extends SwapType>(id: string, chainId: C, swapType: S, signer?: string): Promise<SwapTypeMapping<T[C]>[S] | undefined> {
1561
+ let _swapType: SwapType = swapType;
1562
+ if(swapType===SwapType.FROM_BTC && this.supportsSwapType(chainId, SwapType.SPV_VAULT_FROM_BTC))
1563
+ _swapType = SwapType.SPV_VAULT_FROM_BTC;
1564
+ if(swapType===SwapType.FROM_BTCLN && this.supportsSwapType(chainId, SwapType.FROM_BTCLN_AUTO))
1565
+ _swapType = SwapType.FROM_BTCLN_AUTO;
1566
+
1567
+ const wrapper = this.chains[chainId].wrappers[_swapType];
1568
+ if(wrapper==null) return;
1569
+
1570
+ const result = wrapper.pendingSwaps.get(id)?.deref();
1571
+ if(result!=null) {
1572
+ if (signer != null) {
1573
+ if (result._getInitiator() === signer) return result as any;
1574
+ } else {
1575
+ return result as any;
1576
+ }
1577
+ }
1578
+
1579
+ const queryParams: QueryParams[] = [];
1580
+ if(signer!=null) queryParams.push({key: "initiator", value: signer});
1581
+ queryParams.push({key: "id", value: id});
1582
+ const {unifiedSwapStorage, reviver} = this.chains[chainId];
1583
+ const swap = (await unifiedSwapStorage.query([queryParams], reviver))[0];
1584
+ if(isSwapType(swap, swapType)) return swap;
1585
+ }
1586
+
1587
+ private async syncSwapsForChain<C extends ChainIds<T>>(chainId: C, signer?: string): Promise<void> {
1588
+ const {unifiedSwapStorage, reviver, wrappers} = this.chains[chainId];
1589
+ const queryParams: Array<QueryParams[]> = [];
1590
+ for(let key in wrappers) {
1591
+ const wrapper = wrappers[key as unknown as SwapType];
1592
+ const swapTypeQueryParams: QueryParams[] = [{key: "type", value: wrapper.TYPE}];
1593
+ if(signer!=null) swapTypeQueryParams.push({key: "initiator", value: signer});
1594
+ swapTypeQueryParams.push({key: "state", value: wrapper.pendingSwapStates});
1595
+ queryParams.push(swapTypeQueryParams);
1596
+ }
1597
+ this.logger.debug("_syncSwaps(): Querying swaps swaps for chain "+chainId+"!");
1598
+ const swaps = await unifiedSwapStorage.query(queryParams, reviver);
1599
+ this.logger.debug("_syncSwaps(): Syncing "+swaps.length+" swaps!");
1600
+
1601
+ const changedSwaps: ISwap<T[C]>[] = [];
1602
+ const removeSwaps: ISwap<T[C]>[] = [];
1603
+
1604
+ const assortedSwaps: {[swapType in SwapType]?: ISwap<T[string]>[]} = {};
1605
+ swaps.forEach(swap => {
1606
+ (assortedSwaps[swap.getType()] ??= []).push(swap);
1607
+ });
1608
+
1609
+ for(let key in assortedSwaps) {
1610
+ const swapType = key as unknown as SwapType;
1611
+ const wrapperSwaps = assortedSwaps[swapType];
1612
+ const wrapper: ISwapWrapper<T[C], any> = wrappers[swapType];
1613
+ const result = await wrapper.checkPastSwaps(wrapperSwaps, true);
1614
+ changedSwaps.push(...result.changedSwaps);
1615
+ removeSwaps.push(...result.removeSwaps);
1616
+ }
1617
+
1618
+ this.logger.debug("_syncSwaps(): Done syncing "+swaps.length+" swaps, saving "+changedSwaps.length+" changed swaps, removing "+removeSwaps.length+" swaps!");
1619
+ await unifiedSwapStorage.saveAll(changedSwaps);
1620
+ await unifiedSwapStorage.removeAll(removeSwaps);
1621
+
1622
+ changedSwaps.forEach(swap => swap._emitEvent());
1623
+ removeSwaps.forEach(swap => swap._emitEvent());
1624
+ }
1625
+
1626
+ /**
1627
+ * Synchronizes swaps from chain, this is usually ran when SDK is initialized, deletes expired quotes
1628
+ *
1629
+ * @param chainId
1630
+ * @param signer
1631
+ */
1632
+ async _syncSwaps<C extends ChainIds<T>>(chainId?: C, signer?: string): Promise<void> {
1633
+ if(chainId==null) {
1634
+ await Promise.all(Object.keys(this.chains).map((chainId) => {
1635
+ return this.syncSwapsForChain(chainId, signer);
1636
+ }));
1637
+ } else {
1638
+ await this.syncSwapsForChain(chainId, signer);
1639
+ }
1640
+ }
1641
+
1642
+ /**
1643
+ * Attempts to recover partial swap data from on-chain historical data
1644
+ *
1645
+ * @param chainId
1646
+ * @param signer
1647
+ * @param startBlockheight
1648
+ */
1649
+ async recoverSwaps<C extends ChainIds<T>>(chainId: C, signer: string, startBlockheight?: number): Promise<ISwap<T[C]>[]> {
1650
+ const {swapContract, unifiedSwapStorage, reviver, wrappers} = this.chains[chainId];
1651
+
1652
+ if(swapContract.getHistoricalSwaps==null) throw new Error(`Historical swap recovery is not supported for ${chainId}`);
1653
+
1654
+ const {swaps} = await swapContract.getHistoricalSwaps(signer);
1655
+
1656
+ const escrowHashes = Object.keys(swaps);
1657
+ this.logger.debug(`recoverSwaps(): Loaded on-chain data for ${escrowHashes.length} swaps`);
1658
+ this.logger.debug(`recoverSwaps(): Fetching if swap escrowHashes are known: ${escrowHashes.join(", ")}`);
1659
+ const knownSwapsArray = await unifiedSwapStorage.query([[{key: "escrowHash", value: escrowHashes}]], reviver);
1660
+ const knownSwaps: {[escrowHash: string]: ISwap<T[C]>} = {};
1661
+ knownSwapsArray.forEach(val => {
1662
+ const escrowHash = val._getEscrowHash();
1663
+ if(escrowHash!=null) knownSwaps[escrowHash] = val;
1664
+ });
1665
+ this.logger.debug(`recoverSwaps(): Fetched known swaps escrowHashes: ${Object.keys(knownSwaps).join(", ")}`);
1666
+
1667
+ const recoveredSwaps: ISwap<T[C]>[] = [];
1668
+
1669
+ for(let escrowHash in swaps) {
1670
+ const {init, state} = swaps[escrowHash];
1671
+ const knownSwap = knownSwaps[escrowHash];
1672
+ if(init==null) {
1673
+ if(knownSwap==null) this.logger.warn(`recoverSwaps(): Fetched ${escrowHash} swap state, but swap not found locally!`);
1674
+ //TODO: Update the existing swaps here
1675
+ this.logger.debug(`recoverSwaps(): Skipping ${escrowHash} swap: swap already known and in local storage!`);
1676
+ continue;
1677
+ }
1678
+ if(knownSwap!=null) {
1679
+ //TODO: Update the existing swaps here
1680
+ this.logger.debug(`recoverSwaps(): Skipping ${escrowHash} swap: swap already known and in local storage!`);
1681
+ continue;
1682
+ }
1683
+ const data = init.data;
1684
+
1685
+ //Classify swap
1686
+ let swap: ISwap<T[C]> | undefined | null;
1687
+ let typeIdentified: boolean = false;
1688
+ if(data.getType()===ChainSwapType.HTLC) {
1689
+ if(data.isOfferer(signer)) {
1690
+ //To BTCLN
1691
+ typeIdentified = true;
1692
+ const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isClaimer(val.getAddress(chainId)));
1693
+ swap = await wrappers[SwapType.TO_BTCLN].recoverFromSwapDataAndState(init, state, lp);
1694
+ } else if(data.isClaimer(signer)) {
1695
+ //From BTCLN
1696
+ typeIdentified = true;
1697
+ const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isOfferer(val.getAddress(chainId)));
1698
+ if(this.supportsSwapType(chainId, SwapType.FROM_BTCLN_AUTO)) {
1699
+ swap = await wrappers[SwapType.FROM_BTCLN_AUTO].recoverFromSwapDataAndState(init, state, lp);
1700
+ } else {
1701
+ swap = await wrappers[SwapType.FROM_BTCLN].recoverFromSwapDataAndState(init, state, lp);
1702
+ }
1703
+ }
1704
+ } else if(data.getType()===ChainSwapType.CHAIN_NONCED) {
1705
+ //To BTC
1706
+ typeIdentified = true;
1707
+ const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isClaimer(val.getAddress(chainId)));
1708
+ swap = await wrappers[SwapType.TO_BTC].recoverFromSwapDataAndState(init, state, lp);
1709
+ } else if(data.getType()===ChainSwapType.CHAIN) {
1710
+ //From BTC
1711
+ typeIdentified = true;
1712
+ const lp = this.intermediaryDiscovery.intermediaries.find(val => val.supportsChain(chainId) && data.isOfferer(val.getAddress(chainId)));
1713
+ swap = await wrappers[SwapType.FROM_BTC].recoverFromSwapDataAndState(init, state, lp);
1714
+ }
1715
+
1716
+ if(swap!=null) {
1717
+ recoveredSwaps.push(swap);
1718
+ } else {
1719
+ if(typeIdentified) this.logger.debug(`recoverSwaps(): Swap data type correctly identified but swap returned is null for swap ${escrowHash}`);
1720
+ }
1721
+ }
1722
+
1723
+ this.logger.debug(`recoverSwaps(): Successfully recovered ${recoveredSwaps.length} swaps!`);
1724
+
1725
+ return recoveredSwaps;
1726
+ }
1727
+
1728
+ getToken(tickerOrAddress: string): Token {
1729
+ //Btc tokens - BTC, BTCLN, BTC-LN
1730
+ if(tickerOrAddress==="BTC") return BitcoinTokens.BTC;
1731
+ if(tickerOrAddress==="BTCLN" || tickerOrAddress==="BTC-LN") return BitcoinTokens.BTCLN;
1732
+
1733
+ //Check if the ticker is in format <chainId>-<ticker>, i.e. SOLANA-USDC, STARKNET-WBTC
1734
+ if(tickerOrAddress.includes("-")) {
1735
+ const [chainId, ticker] = tickerOrAddress.split("-");
1736
+ const token = this.tokensByTicker[chainId]?.[ticker];
1737
+ if(token==null) throw new UserError(`Not found ticker: ${ticker} for chainId: ${chainId}`);
1738
+ return token;
1739
+ }
1740
+
1741
+ const possibleTokens: SCToken[] = [];
1742
+ for(let chainId in this.chains) {
1743
+ const chain = this.chains[chainId];
1744
+ if(chain.chainInterface.isValidToken(tickerOrAddress)) {
1745
+ //Try to find in known token addresses
1746
+ const token = this.tokens[chainId]?.[tickerOrAddress];
1747
+ if(token!=null) return token;
1748
+ } else {
1749
+ //Check in known tickers
1750
+ const token = this.tokensByTicker[chainId]?.[tickerOrAddress];
1751
+ if(token!=null) possibleTokens.push(token);
1752
+ }
1753
+ }
1754
+
1755
+ if(possibleTokens.length===0) throw new UserError(`Specified token address or ticker ${tickerOrAddress} not found!`);
1756
+ //In case we've found the token in multiple chains
1757
+ if(possibleTokens.length>1) throw new UserError(`A ticker ${tickerOrAddress} has been found in multiple chains, narrow it down by using <chainId>-${tickerOrAddress} notation`)
1758
+ return possibleTokens[0];
1759
+ }
1760
+
1761
+ /**
1762
+ * Creates a child swapper instance with a given smart chain
1763
+ *
1764
+ * @param chainIdentifier
1765
+ */
1766
+ withChain<ChainIdentifier extends ChainIds<T>>(chainIdentifier: ChainIdentifier): SwapperWithChain<T, ChainIdentifier> {
1767
+ if(this.chains[chainIdentifier]==null) throw new Error("Invalid chain identifier! Unknown chain: "+chainIdentifier);
1768
+ return new SwapperWithChain<T, ChainIdentifier>(this, chainIdentifier as ChainIdentifier);
1769
+ }
1770
+
1771
+ /**
1772
+ * Returns supported smart chains
1773
+ */
1774
+ getSmartChains(): ChainIds<T>[] {
1775
+ return Object.keys(this.chains);
1776
+ }
1777
+
1778
+ /**
1779
+ * Returns whether the SDK supports a given swap type on a given chain based on currently known LPs
1780
+ *
1781
+ * @param chainId
1782
+ * @param swapType
1783
+ */
1784
+ supportsSwapType<
1785
+ ChainIdentifier extends ChainIds<T>,
1786
+ Type extends SwapType
1787
+ >(chainId: ChainIdentifier, swapType: Type): SupportsSwapType<T[ChainIdentifier], Type> {
1788
+ return (this.chains[chainId]?.wrappers[swapType] != null) as any;
1789
+ }
1790
+
1791
+ /**
1792
+ * Returns type of the swap based on input and output tokens specified
1793
+ *
1794
+ * @param srcToken
1795
+ * @param dstToken
1796
+ */
1797
+ getSwapType<C extends ChainIds<T>>(srcToken: BtcToken<true>, dstToken: SCToken<C>): (SupportsSwapType<T[C], SwapType.FROM_BTCLN_AUTO> extends true ? SwapType.FROM_BTCLN_AUTO : SwapType.FROM_BTCLN);
1798
+ getSwapType<C extends ChainIds<T>>(srcToken: BtcToken<false>, dstToken: SCToken<C>): (SupportsSwapType<T[C], SwapType.SPV_VAULT_FROM_BTC> extends true ? SwapType.SPV_VAULT_FROM_BTC : SwapType.FROM_BTC);
1799
+ getSwapType<C extends ChainIds<T>>(srcToken: SCToken<C>, dstToken: BtcToken<false>): SwapType.TO_BTC;
1800
+ getSwapType<C extends ChainIds<T>>(srcToken: SCToken<C>, dstToken: BtcToken<true>): SwapType.TO_BTCLN;
1801
+ getSwapType<C extends ChainIds<T>>(srcToken: Token<C>, dstToken: Token<C>): SwapType.FROM_BTCLN_AUTO | SwapType.FROM_BTCLN | SwapType.SPV_VAULT_FROM_BTC | SwapType.FROM_BTC | SwapType.TO_BTC | SwapType.TO_BTCLN;
1802
+ getSwapType<C extends ChainIds<T>>(srcToken: Token<C>, dstToken: Token<C>): SwapType.FROM_BTCLN_AUTO | SwapType.FROM_BTCLN | SwapType.SPV_VAULT_FROM_BTC | SwapType.FROM_BTC | SwapType.TO_BTC | SwapType.TO_BTCLN {
1803
+ if(isSCToken(srcToken)) {
1804
+ if(!isBtcToken(dstToken)) throw new Error("Swap not supported");
1805
+ if(dstToken.lightning) {
1806
+ return SwapType.TO_BTCLN;
1807
+ } else {
1808
+ return SwapType.TO_BTC;
1809
+ }
1810
+ } else if(isBtcToken(srcToken)) {
1811
+ if(!isSCToken(dstToken)) throw new Error("Swap not supported");
1812
+ if(srcToken.lightning) {
1813
+ if(this.supportsSwapType(dstToken.chainId, SwapType.FROM_BTCLN_AUTO)) {
1814
+ return SwapType.FROM_BTCLN_AUTO;
1815
+ } else {
1816
+ return SwapType.FROM_BTCLN;
1817
+ }
1818
+ } else {
1819
+ if(this.supportsSwapType(dstToken.chainId, SwapType.SPV_VAULT_FROM_BTC)) {
1820
+ return SwapType.SPV_VAULT_FROM_BTC;
1821
+ } else {
1822
+ return SwapType.FROM_BTC;
1823
+ }
1824
+ }
1825
+ }
1826
+ throw new Error("Swap not supported");
1827
+ }
1828
+
1829
+ readonly SwapTypeInfo = {
1830
+ [SwapType.TO_BTC]: {
1831
+ requiresInputWallet: true,
1832
+ requiresOutputWallet: false,
1833
+ supportsGasDrop: false
1834
+ },
1835
+ [SwapType.TO_BTCLN]: {
1836
+ requiresInputWallet: true,
1837
+ requiresOutputWallet: false,
1838
+ supportsGasDrop: false
1839
+ },
1840
+ [SwapType.FROM_BTC]: {
1841
+ requiresInputWallet: false,
1842
+ requiresOutputWallet: true,
1843
+ supportsGasDrop: false
1844
+ },
1845
+ [SwapType.FROM_BTCLN]: {
1846
+ requiresInputWallet: false,
1847
+ requiresOutputWallet: true,
1848
+ supportsGasDrop: false
1849
+ },
1850
+ [SwapType.SPV_VAULT_FROM_BTC]: {
1851
+ requiresInputWallet: true,
1852
+ requiresOutputWallet: false,
1853
+ supportsGasDrop: true
1854
+ },
1855
+ [SwapType.FROM_BTCLN_AUTO]: {
1856
+ requiresInputWallet: false,
1857
+ requiresOutputWallet: false,
1858
+ supportsGasDrop: true
1859
+ },
1860
+ [SwapType.TRUSTED_FROM_BTC]: {
1861
+ requiresInputWallet: false,
1862
+ requiresOutputWallet: false,
1863
+ supportsGasDrop: false
1864
+ },
1865
+ [SwapType.TRUSTED_FROM_BTCLN]: {
1866
+ requiresInputWallet: false,
1867
+ requiresOutputWallet: false,
1868
+ supportsGasDrop: false
1869
+ }
1870
+ } as const;
1871
+
1872
+ /**
1873
+ * Returns minimum/maximum limits for inputs and outputs for a swap between given tokens
1874
+ *
1875
+ * @param srcToken
1876
+ * @param dstToken
1877
+ */
1878
+ getSwapLimits<C extends ChainIds<T>, A extends Token<C>, B extends Token<C>>(srcToken: A, dstToken: B): {
1879
+ input: {min: TokenAmount<string, A>, max?: TokenAmount<string, A>},
1880
+ output: {min: TokenAmount<string, B>, max?: TokenAmount<string, B>}
1881
+ } {
1882
+ const swapType = this.getSwapType(srcToken, dstToken);
1883
+ const scToken = isSCToken(srcToken) ? srcToken : isSCToken(dstToken) ? dstToken : null;
1884
+ if(scToken==null) throw new Error("At least one token needs to be a smart chain token!");
1885
+ const result: {input: {min?: bigint, max?: bigint}, output: {min?: bigint, max?: bigint}} = {
1886
+ input: {},
1887
+ output: {}
1888
+ };
1889
+ for(let lp of this.intermediaryDiscovery.intermediaries) {
1890
+ const lpMinMax = lp.getSwapLimits(swapType, scToken.chainId, scToken.address);
1891
+ if(lpMinMax==null) continue;
1892
+ result.input.min = result.input.min==null ? lpMinMax.input.min : bigIntMin(result.input.min, lpMinMax.input.min);
1893
+ result.input.max = result.input.max==null ? lpMinMax.input.max : bigIntMax(result.input.max, lpMinMax.input.max);
1894
+ result.output.min = result.output.min==null ? lpMinMax.output.min : bigIntMin(result.output.min, lpMinMax.output.min);
1895
+ result.output.max = result.output.max==null ? lpMinMax.output.max : bigIntMax(result.output.max, lpMinMax.output.max);
1896
+ }
1897
+ return {
1898
+ input: {
1899
+ min: toTokenAmount(result.input.min ?? 1n, srcToken, this.prices),
1900
+ max: result.input.max==null ? undefined : toTokenAmount(result.input.max, srcToken, this.prices),
1901
+ },
1902
+ output: {
1903
+ min: toTokenAmount(result.output.min ?? 1n, dstToken, this.prices),
1904
+ max: result.output.max==null ? undefined : toTokenAmount(result.output.max, dstToken, this.prices),
1905
+ }
1906
+ }
1907
+ }
1908
+
1909
+ /**
1910
+ * Returns supported tokens for a given direction
1911
+ *
1912
+ * @param input Whether to return input tokens or output tokens
1913
+ */
1914
+ getSupportedTokens(input: boolean): Token[] {
1915
+ const tokens: {[chainId: string]: Set<string>} = {};
1916
+ let lightning = false;
1917
+ let btc = false;
1918
+ this.intermediaryDiscovery.intermediaries.forEach(lp => {
1919
+ for(let swapType of [SwapType.TO_BTC, SwapType.TO_BTCLN, SwapType.FROM_BTC, SwapType.FROM_BTCLN, SwapType.SPV_VAULT_FROM_BTC, SwapType.FROM_BTCLN_AUTO]) {
1920
+ if(lp.services[swapType]?.chainTokens==null) continue;
1921
+ for(let chainId of this.getSmartChains()) {
1922
+ if(this.supportsSwapType(chainId, SwapType.SPV_VAULT_FROM_BTC) ? swapType===SwapType.FROM_BTC : swapType===SwapType.SPV_VAULT_FROM_BTC) continue;
1923
+ if(this.supportsSwapType(chainId, SwapType.FROM_BTCLN_AUTO) ? swapType===SwapType.FROM_BTCLN : swapType===SwapType.FROM_BTCLN_AUTO) continue;
1924
+ const chainTokens = lp.services[swapType]?.chainTokens?.[chainId];
1925
+ if(chainTokens==null) continue;
1926
+ for (let tokenAddress of chainTokens) {
1927
+ if(input) {
1928
+ if(swapType===SwapType.TO_BTC || swapType===SwapType.TO_BTCLN) {
1929
+ tokens[chainId] ??= new Set();
1930
+ tokens[chainId].add(tokenAddress);
1931
+ }
1932
+ if(swapType===SwapType.FROM_BTCLN || swapType===SwapType.FROM_BTCLN_AUTO) {
1933
+ lightning = true;
1934
+ }
1935
+ if(swapType===SwapType.FROM_BTC || swapType===SwapType.SPV_VAULT_FROM_BTC) {
1936
+ btc = true;
1937
+ }
1938
+ } else {
1939
+ if(swapType===SwapType.FROM_BTCLN || swapType===SwapType.FROM_BTC || swapType===SwapType.SPV_VAULT_FROM_BTC || swapType===SwapType.FROM_BTCLN_AUTO) {
1940
+ tokens[chainId] ??= new Set();
1941
+ tokens[chainId].add(tokenAddress);
1942
+ }
1943
+ if(swapType===SwapType.TO_BTCLN) {
1944
+ lightning = true;
1945
+ }
1946
+ if(swapType===SwapType.TO_BTC) {
1947
+ btc = true;
1948
+ }
1949
+ }
1950
+ }
1951
+ }
1952
+ }
1953
+ });
1954
+ const output: Token[] = [];
1955
+ if(lightning) output.push(BitcoinTokens.BTCLN);
1956
+ if(btc) output.push(BitcoinTokens.BTC);
1957
+ for(let chainId in tokens) {
1958
+ tokens[chainId].forEach(tokenAddress => {
1959
+ const token = this.tokens?.[chainId]?.[tokenAddress];
1960
+ if(token!=null) output.push(token);
1961
+ })
1962
+ }
1963
+ return output;
1964
+ }
1965
+
1966
+ /**
1967
+ * Returns a set of supported tokens by all the intermediaries offering a specific swap service
1968
+ *
1969
+ * @param _swapType Swap service type to check supported tokens for
1970
+ */
1971
+ private getSupportedTokensForSwapType(_swapType: SwapType): SCToken[] {
1972
+ const tokens: {[chainId: string]: Set<string>} = {};
1973
+ this.intermediaryDiscovery.intermediaries.forEach(lp => {
1974
+ for(let chainId of this.getSmartChains()) {
1975
+ let swapType = _swapType;
1976
+ if(swapType===SwapType.FROM_BTC && this.supportsSwapType(chainId, SwapType.SPV_VAULT_FROM_BTC)) swapType = SwapType.SPV_VAULT_FROM_BTC;
1977
+ if(swapType===SwapType.FROM_BTCLN && this.supportsSwapType(chainId, SwapType.FROM_BTCLN_AUTO)) swapType = SwapType.FROM_BTCLN_AUTO;
1978
+ if(lp.services[swapType]?.chainTokens==null) break;
1979
+ const chainTokens = lp.services[swapType]?.chainTokens?.[chainId];
1980
+ if(chainTokens==null) continue;
1981
+ for(let tokenAddress of chainTokens) {
1982
+ tokens[chainId] ??= new Set();
1983
+ tokens[chainId].add(tokenAddress);
1984
+ }
1985
+ }
1986
+ });
1987
+ const output: SCToken[] = [];
1988
+ for(let chainId in tokens) {
1989
+ tokens[chainId].forEach(tokenAddress => {
1990
+ const token = this.tokens?.[chainId]?.[tokenAddress];
1991
+ if(token!=null) output.push(token);
1992
+ })
1993
+ }
1994
+ return output;
1995
+ }
1996
+
1997
+ /**
1998
+ * Returns the set of supported token addresses by all the intermediaries we know of offering a specific swapType service
1999
+ *
2000
+ * @param chainIdentifier
2001
+ * @param swapType Specific swap type for which to obtain supported tokens
2002
+ */
2003
+ private getSupportedTokenAddresses<ChainIdentifier extends ChainIds<T>>(chainIdentifier: ChainIdentifier, swapType: SwapType): Set<string> {
2004
+ const set = new Set<string>();
2005
+ this.intermediaryDiscovery.intermediaries.forEach(lp => {
2006
+ const chainTokens = lp.services[swapType]?.chainTokens?.[chainIdentifier];
2007
+ if(chainTokens==null) return;
2008
+ chainTokens.forEach(token => set.add(token));
2009
+ });
2010
+ return set;
2011
+ }
2012
+
2013
+ /**
2014
+ * Returns tokens that you can swap to (if input=true) from a given token,
2015
+ * or tokens that you can swap from (if input=false) to a given token
2016
+ */
2017
+ getSwapCounterTokens(token: Token, input: boolean): Token[] {
2018
+ if(isSCToken(token)) {
2019
+ const result: Token[] = [];
2020
+ if(input) {
2021
+ //TO_BTC or TO_BTCLN
2022
+ if(this.getSupportedTokenAddresses(token.chainId, SwapType.TO_BTCLN).has(token.address)) {
2023
+ result.push(BitcoinTokens.BTCLN);
2024
+ }
2025
+ if(this.getSupportedTokenAddresses(token.chainId, SwapType.TO_BTC).has(token.address)) {
2026
+ result.push(BitcoinTokens.BTC);
2027
+ }
2028
+ } else {
2029
+ //FROM_BTC or FROM_BTCLN
2030
+ const fromLightningSwapType = this.supportsSwapType(token.chainId, SwapType.FROM_BTCLN_AUTO) ? SwapType.FROM_BTCLN_AUTO : SwapType.FROM_BTCLN;
2031
+ if(this.getSupportedTokenAddresses(token.chainId, fromLightningSwapType).has(token.address)) {
2032
+ result.push(BitcoinTokens.BTCLN);
2033
+ }
2034
+ const fromOnchainSwapType = this.supportsSwapType(token.chainId, SwapType.SPV_VAULT_FROM_BTC) ? SwapType.SPV_VAULT_FROM_BTC : SwapType.FROM_BTC;
2035
+ if(this.getSupportedTokenAddresses(token.chainId, fromOnchainSwapType).has(token.address)) {
2036
+ result.push(BitcoinTokens.BTC);
2037
+ }
2038
+ }
2039
+ return result;
2040
+ } else {
2041
+ if(input) {
2042
+ if(token.lightning) {
2043
+ return this.getSupportedTokensForSwapType(SwapType.FROM_BTCLN);
2044
+ } else {
2045
+ return this.getSupportedTokensForSwapType(SwapType.FROM_BTC);
2046
+ }
2047
+ } else {
2048
+ if(token.lightning) {
2049
+ return this.getSupportedTokensForSwapType(SwapType.TO_BTCLN);
2050
+ } else {
2051
+ return this.getSupportedTokensForSwapType(SwapType.TO_BTC);
2052
+ }
2053
+ }
2054
+ }
2055
+ }
2056
+
2057
+
2058
+ ///////////////////////////////////
2059
+ /// Deprecated
2060
+
2061
+ /**
2062
+ * Returns swap bounds (minimums & maximums) for different swap types & tokens
2063
+ * @deprecated Use getSwapLimits() instead!
2064
+ */
2065
+ getSwapBounds<ChainIdentifier extends ChainIds<T>>(chainIdentifier: ChainIdentifier): SwapBounds;
2066
+ getSwapBounds(): MultichainSwapBounds;
2067
+ getSwapBounds<ChainIdentifier extends ChainIds<T>>(chainIdentifier?: ChainIdentifier): SwapBounds | MultichainSwapBounds {
2068
+ if(chainIdentifier==null) {
2069
+ return this.intermediaryDiscovery.getMultichainSwapBounds();
2070
+ } else {
2071
+ return this.intermediaryDiscovery.getSwapBounds(chainIdentifier);
2072
+ }
2073
+ }
2074
+
2075
+ /**
2076
+ * Returns maximum possible swap amount
2077
+ * @deprecated Use getSwapLimits() instead!
2078
+ *
2079
+ * @param chainIdentifier
2080
+ * @param type Type of the swap
2081
+ * @param token Token of the swap
2082
+ */
2083
+ getMaximum<ChainIdentifier extends ChainIds<T>>(chainIdentifier: ChainIdentifier, type: SwapType, token: string): bigint {
2084
+ if(this.intermediaryDiscovery!=null) {
2085
+ const max = this.intermediaryDiscovery.getSwapMaximum(chainIdentifier, type, token);
2086
+ if(max!=null) return BigInt(max);
2087
+ }
2088
+ return 0n;
2089
+ }
2090
+
2091
+ /**
2092
+ * Returns minimum possible swap amount
2093
+ * @deprecated Use getSwapLimits() instead!
2094
+ *
2095
+ * @param chainIdentifier
2096
+ * @param type Type of swap
2097
+ * @param token Token of the swap
2098
+ */
2099
+ getMinimum<ChainIdentifier extends ChainIds<T>>(chainIdentifier: ChainIdentifier, type: SwapType, token: string): bigint {
2100
+ if(this.intermediaryDiscovery!=null) {
2101
+ const min = this.intermediaryDiscovery.getSwapMinimum(chainIdentifier, type, token);
2102
+ if(min!=null) return BigInt(min);
2103
+ }
2104
+ return 0n;
2105
+ }
2106
+
2107
+ }