@atomiqlabs/sdk 7.0.12 → 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} +37 -19
  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} +113 -72
  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,1078 @@
1
+ import {decode as bolt11Decode} from "@atomiqlabs/bolt11";
2
+ import {SwapType} from "../../../../enums/SwapType";
3
+ import {
4
+ ChainSwapType,
5
+ ChainType, isAbstractSigner,
6
+ SwapClaimWitnessMessage,
7
+ SwapCommitState,
8
+ SwapCommitStateType,
9
+ SwapData,
10
+ } from "@atomiqlabs/base";
11
+ import {Buffer} from "buffer";
12
+ import {LNURL} from "../../../../lnurl/LNURL";
13
+ import {UserError} from "../../../../errors/UserError";
14
+ import {
15
+ IntermediaryAPI,
16
+ InvoiceStatusResponse,
17
+ InvoiceStatusResponseCodes
18
+ } from "../../../../intermediaries/apis/IntermediaryAPI";
19
+ import {IntermediaryError} from "../../../../errors/IntermediaryError";
20
+ import {
21
+ extendAbortController,
22
+ toBigInt
23
+ } from "../../../../utils/Utils";
24
+ import {Fee} from "../../../../types/fees/Fee";
25
+ import {IAddressSwap} from "../../../IAddressSwap";
26
+ import {FromBTCLNAutoDefinition, FromBTCLNAutoWrapper} from "./FromBTCLNAutoWrapper";
27
+ import {ISwapWithGasDrop} from "../../../ISwapWithGasDrop";
28
+ import {MinimalLightningNetworkWalletInterface} from "../../../../bitcoin/wallet/MinimalLightningNetworkWalletInterface";
29
+ import {IClaimableSwap} from "../../../IClaimableSwap";
30
+ import {IEscrowSwap, IEscrowSwapInit, isIEscrowSwapInit} from "../../IEscrowSwap";
31
+ import {FeeType} from "../../../../enums/FeeType";
32
+ import {ppmToPercentage} from "../../../../types/fees/PercentagePPM";
33
+ import {TokenAmount, toTokenAmount} from "../../../../types/TokenAmount";
34
+ import {BitcoinTokens, BtcToken, SCToken, Token} from "../../../../types/Token";
35
+ import {getLogger, LoggerType} from "../../../../utils/Logger";
36
+ import {timeoutPromise} from "../../../../utils/TimeoutUtils";
37
+ import {isLNURLWithdraw, LNURLWithdraw, LNURLWithdrawParamsWithUrl} from "../../../../types/lnurl/LNURLWithdraw";
38
+ import {
39
+ deserializePriceInfoType,
40
+ isPriceInfoType,
41
+ PriceInfoType,
42
+ serializePriceInfoType
43
+ } from "../../../../types/PriceInfoType";
44
+
45
+ /**
46
+ * State enum for FromBTCLNAuto swaps
47
+ * @category Swaps
48
+ */
49
+ export enum FromBTCLNAutoSwapState {
50
+ FAILED = -4,
51
+ QUOTE_EXPIRED = -3,
52
+ QUOTE_SOFT_EXPIRED = -2,
53
+ EXPIRED = -1,
54
+ PR_CREATED = 0,
55
+ PR_PAID = 1,
56
+ CLAIM_COMMITED = 2,
57
+ CLAIM_CLAIMED = 3
58
+ }
59
+
60
+ export type FromBTCLNAutoSwapInit<T extends SwapData> = IEscrowSwapInit<T> & {
61
+ pr: string,
62
+ secret: string,
63
+ initialSwapData: T,
64
+
65
+ btcAmountSwap: bigint,
66
+ btcAmountGas: bigint,
67
+
68
+ gasSwapFeeBtc: bigint,
69
+ gasSwapFee: bigint,
70
+ gasPricingInfo?: PriceInfoType,
71
+
72
+ lnurl?: string,
73
+ lnurlK1?: string,
74
+ lnurlCallback?: string
75
+ };
76
+
77
+ export function isFromBTCLNAutoSwapInit<T extends SwapData>(obj: any): obj is FromBTCLNAutoSwapInit<T> {
78
+ return typeof obj.pr==="string" &&
79
+ typeof obj.secret==="string" &&
80
+ typeof obj.btcAmountSwap==="bigint" &&
81
+ typeof obj.btcAmountGas==="bigint" &&
82
+ typeof obj.gasSwapFeeBtc==="bigint" &&
83
+ typeof obj.gasSwapFee==="bigint" &&
84
+ (obj.gasPricingInfo==null || isPriceInfoType(obj.gasPricingInfo)) &&
85
+ (obj.lnurl==null || typeof(obj.lnurl)==="string") &&
86
+ (obj.lnurlK1==null || typeof(obj.lnurlK1)==="string") &&
87
+ (obj.lnurlCallback==null || typeof(obj.lnurlCallback)==="string") &&
88
+ isIEscrowSwapInit(obj);
89
+ }
90
+
91
+ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
92
+ extends IEscrowSwap<T, FromBTCLNAutoDefinition<T>>
93
+ implements IAddressSwap, ISwapWithGasDrop<T>, IClaimableSwap<T, FromBTCLNAutoDefinition<T>, FromBTCLNAutoSwapState> {
94
+
95
+ protected readonly logger: LoggerType;
96
+ protected readonly inputToken: BtcToken<true> = BitcoinTokens.BTCLN;
97
+ protected readonly TYPE = SwapType.FROM_BTCLN_AUTO;
98
+
99
+ protected readonly lnurlFailSignal: AbortController = new AbortController();
100
+
101
+ protected readonly pr: string;
102
+ protected readonly secret: string;
103
+ protected initialSwapData: T["Data"];
104
+
105
+ protected readonly btcAmountSwap: bigint;
106
+ protected readonly btcAmountGas: bigint;
107
+
108
+ protected readonly gasSwapFeeBtc: bigint;
109
+ protected readonly gasSwapFee: bigint;
110
+ gasPricingInfo?: PriceInfoType;
111
+
112
+ lnurl?: string;
113
+ lnurlK1?: string;
114
+ lnurlCallback?: string;
115
+ prPosted?: boolean = false;
116
+
117
+ protected getSwapData(): T["Data"] {
118
+ return this.data ?? this.initialSwapData;
119
+ }
120
+
121
+ constructor(wrapper: FromBTCLNAutoWrapper<T>, init: FromBTCLNAutoSwapInit<T["Data"]>);
122
+ constructor(wrapper: FromBTCLNAutoWrapper<T>, obj: any);
123
+ constructor(
124
+ wrapper: FromBTCLNAutoWrapper<T>,
125
+ initOrObject: FromBTCLNAutoSwapInit<T["Data"]> | any
126
+ ) {
127
+ if(isFromBTCLNAutoSwapInit(initOrObject) && initOrObject.url!=null) initOrObject.url += "/frombtcln_auto";
128
+ super(wrapper, initOrObject);
129
+ if(isFromBTCLNAutoSwapInit(initOrObject)) {
130
+ this.state = FromBTCLNAutoSwapState.PR_CREATED;
131
+ this.pr = initOrObject.pr;
132
+ this.secret = initOrObject.secret;
133
+ this.initialSwapData = initOrObject.initialSwapData;
134
+ this.btcAmountSwap = initOrObject.btcAmountSwap;
135
+ this.btcAmountGas = initOrObject.btcAmountGas;
136
+ this.gasSwapFeeBtc = initOrObject.gasSwapFeeBtc;
137
+ this.gasSwapFee = initOrObject.gasSwapFee;
138
+ this.gasPricingInfo = initOrObject.gasPricingInfo;
139
+ this.lnurl = initOrObject.lnurl;
140
+ this.lnurlK1 = initOrObject.lnurlK1;
141
+ this.lnurlCallback = initOrObject.lnurlCallback;
142
+ } else {
143
+ this.pr = initOrObject.pr;
144
+ this.secret = initOrObject.secret;
145
+
146
+ if(initOrObject.initialSwapData==null) {
147
+ this.initialSwapData = this.data!;
148
+ } else {
149
+ this.initialSwapData = SwapData.deserialize<T["Data"]>(initOrObject.initialSwapData);
150
+ }
151
+
152
+ this.btcAmountSwap = toBigInt(initOrObject.btcAmountSwap);
153
+ this.btcAmountGas = toBigInt(initOrObject.btcAmountGas);
154
+ this.gasSwapFeeBtc = toBigInt(initOrObject.gasSwapFeeBtc);
155
+ this.gasSwapFee = toBigInt(initOrObject.gasSwapFee);
156
+ this.gasPricingInfo = deserializePriceInfoType(initOrObject.gasPricingInfo);
157
+
158
+ this.commitTxId = initOrObject.commitTxId;
159
+ this.claimTxId = initOrObject.claimTxId;
160
+
161
+ this.lnurl = initOrObject.lnurl;
162
+ this.lnurlK1 = initOrObject.lnurlK1;
163
+ this.lnurlCallback = initOrObject.lnurlCallback;
164
+ this.prPosted = initOrObject.prPosted;
165
+ }
166
+ this.tryRecomputeSwapPrice();
167
+ this.logger = getLogger("FromBTCLNAuto("+this.getIdentifierHashString()+"): ");
168
+ }
169
+
170
+ protected upgradeVersion() { /*NOOP*/ }
171
+
172
+ /**
173
+ * In case swapFee in BTC is not supplied it recalculates it based on swap price
174
+ * @protected
175
+ */
176
+ protected tryRecomputeSwapPrice() {
177
+ if(this.pricingInfo==null) return;
178
+ if(this.pricingInfo.swapPriceUSatPerToken==null) {
179
+ const priceUsdPerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
180
+ this.pricingInfo = this.wrapper.prices.recomputePriceInfoReceive(
181
+ this.chainIdentifier,
182
+ this.btcAmountSwap,
183
+ this.pricingInfo.satsBaseFee,
184
+ this.pricingInfo.feePPM,
185
+ this.getOutputAmountWithoutFee(),
186
+ this.getSwapData().getToken()
187
+ );
188
+ this.pricingInfo.realPriceUsdPerBitcoin = priceUsdPerBtc;
189
+ }
190
+ }
191
+
192
+
193
+ //////////////////////////////
194
+ //// Pricing
195
+
196
+ async refreshPriceData(): Promise<void> {
197
+ if(this.pricingInfo==null) return;
198
+ const usdPricePerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
199
+ this.pricingInfo = await this.wrapper.prices.isValidAmountReceive(
200
+ this.chainIdentifier,
201
+ this.btcAmountSwap,
202
+ this.pricingInfo.satsBaseFee,
203
+ this.pricingInfo.feePPM,
204
+ this.getOutputAmountWithoutFee(),
205
+ this.getSwapData().getToken()
206
+ );
207
+ this.pricingInfo.realPriceUsdPerBitcoin = usdPricePerBtc;
208
+ }
209
+
210
+
211
+ //////////////////////////////
212
+ //// Getters & utils
213
+
214
+ _getEscrowHash(): string | null {
215
+ //Use claim hash in case the data is not yet known
216
+ return this.data == null ? this.initialSwapData?.getClaimHash() : this.data?.getEscrowHash();
217
+ }
218
+
219
+ _getInitiator(): string {
220
+ return this.getSwapData().getClaimer();
221
+ }
222
+
223
+ getId(): string {
224
+ return this.getIdentifierHashString();
225
+ }
226
+
227
+ getOutputAddress(): string | null {
228
+ return this._getInitiator();
229
+ }
230
+
231
+ getOutputTxId(): string | null {
232
+ return this.claimTxId ?? null;
233
+ }
234
+
235
+ requiresAction(): boolean {
236
+ return this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED;
237
+ }
238
+
239
+ protected getIdentifierHashString(): string {
240
+ const paymentHashBuffer = this.getPaymentHash();
241
+ if(this.randomNonce==null) return paymentHashBuffer?.toString("hex");
242
+ return paymentHashBuffer.toString("hex") + this.randomNonce;
243
+ }
244
+
245
+ protected getPaymentHash(): Buffer {
246
+ const decodedPR = bolt11Decode(this.pr);
247
+ if(decodedPR.tagsObject.payment_hash==null) throw new Error("Swap invoice doesn't contain payment hash field!");
248
+ return Buffer.from(decodedPR.tagsObject.payment_hash, "hex");
249
+ }
250
+
251
+ getInputAddress(): string | null {
252
+ return this.lnurl ?? this.pr;
253
+ }
254
+
255
+ getInputTxId(): string {
256
+ return this.getPaymentHash().toString("hex");
257
+ }
258
+
259
+ /**
260
+ * Returns the lightning network BOLT11 invoice that needs to be paid as an input to the swap
261
+ */
262
+ getAddress(): string {
263
+ return this.pr;
264
+ }
265
+
266
+ getHyperlink(): string {
267
+ return "lightning:"+this.pr.toUpperCase();
268
+ }
269
+
270
+ /**
271
+ * Returns the timeout time (in UNIX milliseconds) when the swap will definitelly be considered as expired
272
+ * if the LP doesn't make it expired sooner
273
+ */
274
+ getDefinitiveExpiryTime(): number {
275
+ const decoded = bolt11Decode(this.pr);
276
+ if(decoded.tagsObject.min_final_cltv_expiry==null) throw new Error("Swap invoice doesn't contain final ctlv delta field!");
277
+ if(decoded.timeExpireDate==null) throw new Error("Swap invoice doesn't contain expiry date field!");
278
+ const finalCltvExpiryDelta = decoded.tagsObject.min_final_cltv_expiry ?? 144;
279
+ const finalCltvExpiryDelay = finalCltvExpiryDelta * this.wrapper.options.bitcoinBlocktime * this.wrapper.options.safetyFactor;
280
+ return (decoded.timeExpireDate + finalCltvExpiryDelay)*1000;
281
+ }
282
+
283
+ /**
284
+ * Returns timeout time (in UNIX milliseconds) when the swap htlc will expire
285
+ */
286
+ getHtlcTimeoutTime(): number | null {
287
+ return this.data==null ? null : Number(this.wrapper.getHtlcTimeout(this.data))*1000;
288
+ }
289
+
290
+ isFinished(): boolean {
291
+ return this.state===FromBTCLNAutoSwapState.CLAIM_CLAIMED || this.state===FromBTCLNAutoSwapState.QUOTE_EXPIRED || this.state===FromBTCLNAutoSwapState.FAILED;
292
+ }
293
+
294
+ isClaimable(): boolean {
295
+ return this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED;
296
+ }
297
+
298
+ isSuccessful(): boolean {
299
+ return this.state===FromBTCLNAutoSwapState.CLAIM_CLAIMED;
300
+ }
301
+
302
+ isFailed(): boolean {
303
+ return this.state===FromBTCLNAutoSwapState.FAILED || this.state===FromBTCLNAutoSwapState.EXPIRED;
304
+ }
305
+
306
+ isQuoteExpired(): boolean {
307
+ return this.state===FromBTCLNAutoSwapState.QUOTE_EXPIRED;
308
+ }
309
+
310
+ isQuoteSoftExpired(): boolean {
311
+ return this.state===FromBTCLNAutoSwapState.QUOTE_EXPIRED;
312
+ }
313
+
314
+ _verifyQuoteDefinitelyExpired(): Promise<boolean> {
315
+ return Promise.resolve(this.getDefinitiveExpiryTime()<Date.now());
316
+ }
317
+
318
+ verifyQuoteValid(): Promise<boolean> {
319
+ return Promise.resolve(this.getQuoteExpiry()>Date.now());
320
+ }
321
+
322
+
323
+ //////////////////////////////
324
+ //// Amounts & fees
325
+
326
+ protected getLightningInvoiceSats(): bigint {
327
+ const parsed = bolt11Decode(this.pr);
328
+ if(parsed.millisatoshis==null) throw new Error("Swap invoice doesn't contain msat amount field!");
329
+ return (BigInt(parsed.millisatoshis) + 999n) / 1000n;
330
+ }
331
+
332
+ protected getWatchtowerFeeAmountBtc() {
333
+ return (this.btcAmountGas - this.gasSwapFeeBtc) * this.getSwapData().getClaimerBounty() / this.getSwapData().getTotalDeposit();
334
+ }
335
+
336
+ protected getInputSwapAmountWithoutFee(): bigint {
337
+ return this.btcAmountSwap - this.swapFeeBtc;
338
+ }
339
+
340
+ protected getInputGasAmountWithoutFee(): bigint {
341
+ return this.btcAmountGas - this.gasSwapFeeBtc;
342
+ }
343
+
344
+ protected getInputAmountWithoutFee(): bigint {
345
+ return this.getInputSwapAmountWithoutFee() + this.getInputGasAmountWithoutFee() - this.getWatchtowerFeeAmountBtc();
346
+ }
347
+
348
+ protected getOutputAmountWithoutFee(): bigint {
349
+ return this.getSwapData().getAmount() + this.swapFee;
350
+ }
351
+
352
+ getInputToken(): BtcToken<true> {
353
+ return BitcoinTokens.BTCLN;
354
+ }
355
+
356
+ getInput(): TokenAmount<T["ChainId"], BtcToken<true>> {
357
+ return toTokenAmount(this.getLightningInvoiceSats(), this.inputToken, this.wrapper.prices, this.pricingInfo);
358
+ }
359
+
360
+ getInputWithoutFee(): TokenAmount {
361
+ return toTokenAmount(this.getInputAmountWithoutFee(), this.inputToken, this.wrapper.prices, this.pricingInfo);
362
+ }
363
+
364
+ getOutputToken(): SCToken<T["ChainId"]> {
365
+ return this.wrapper.tokens[this.getSwapData().getToken()];
366
+ }
367
+
368
+ getOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>> {
369
+ return toTokenAmount(this.getSwapData().getAmount(), this.wrapper.tokens[this.getSwapData().getToken()], this.wrapper.prices, this.pricingInfo);
370
+ }
371
+
372
+ getGasDropOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>> {
373
+ return toTokenAmount(
374
+ this.getSwapData().getSecurityDeposit() - this.getSwapData().getClaimerBounty(),
375
+ this.wrapper.tokens[this.getSwapData().getDepositToken()], this.wrapper.prices, this.gasPricingInfo
376
+ );
377
+ }
378
+
379
+ protected getSwapFee(): Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>> {
380
+ if(this.pricingInfo==null) throw new Error("No pricing info known, cannot estimate fee!");
381
+
382
+ const outputToken = this.wrapper.tokens[this.getSwapData().getToken()];
383
+ const gasSwapFeeInOutputToken = this.gasSwapFeeBtc
384
+ * (10n ** BigInt(outputToken.decimals))
385
+ * 1_000_000n
386
+ / this.pricingInfo.swapPriceUSatPerToken;
387
+
388
+ const feeWithoutBaseFee = this.gasSwapFeeBtc + this.swapFeeBtc - this.pricingInfo.satsBaseFee;
389
+ const swapFeePPM = feeWithoutBaseFee * 1000000n / (this.getLightningInvoiceSats() - this.swapFeeBtc - this.gasSwapFeeBtc);
390
+
391
+ const amountInSrcToken = toTokenAmount(this.swapFeeBtc + this.gasSwapFeeBtc, BitcoinTokens.BTCLN, this.wrapper.prices, this.pricingInfo);
392
+ return {
393
+ amountInSrcToken,
394
+ amountInDstToken: toTokenAmount(this.swapFee + gasSwapFeeInOutputToken, outputToken, this.wrapper.prices, this.pricingInfo),
395
+ currentUsdValue: amountInSrcToken.currentUsdValue,
396
+ pastUsdValue: amountInSrcToken.pastUsdValue,
397
+ usdValue: amountInSrcToken.usdValue,
398
+ composition: {
399
+ base: toTokenAmount(this.pricingInfo.satsBaseFee, BitcoinTokens.BTCLN, this.wrapper.prices, this.pricingInfo),
400
+ percentage: ppmToPercentage(swapFeePPM)
401
+ }
402
+ };
403
+ }
404
+
405
+ protected getWatchtowerFee(): Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>> {
406
+ if(this.pricingInfo==null) throw new Error("No pricing info known, cannot estimate fee!");
407
+
408
+ const btcWatchtowerFee = this.getWatchtowerFeeAmountBtc();
409
+ const outputToken = this.wrapper.tokens[this.getSwapData().getToken()];
410
+ const watchtowerFeeInOutputToken = btcWatchtowerFee
411
+ * (10n ** BigInt(outputToken.decimals))
412
+ * 1_000_000n
413
+ / this.pricingInfo.swapPriceUSatPerToken;
414
+
415
+ const amountInSrcToken = toTokenAmount(btcWatchtowerFee, BitcoinTokens.BTCLN, this.wrapper.prices, this.pricingInfo);
416
+ return {
417
+ amountInSrcToken,
418
+ amountInDstToken: toTokenAmount(watchtowerFeeInOutputToken, outputToken, this.wrapper.prices, this.pricingInfo),
419
+ currentUsdValue: amountInSrcToken.currentUsdValue,
420
+ usdValue: amountInSrcToken.usdValue,
421
+ pastUsdValue: amountInSrcToken.pastUsdValue
422
+ };
423
+ }
424
+
425
+
426
+ getFee(): Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>> {
427
+ const swapFee = this.getSwapFee();
428
+ const watchtowerFee = this.getWatchtowerFee();
429
+
430
+ const amountInSrcToken = toTokenAmount(
431
+ swapFee.amountInSrcToken.rawAmount + watchtowerFee.amountInSrcToken.rawAmount,
432
+ BitcoinTokens.BTCLN, this.wrapper.prices, this.pricingInfo
433
+ );
434
+ return {
435
+ amountInSrcToken,
436
+ amountInDstToken: toTokenAmount(
437
+ swapFee.amountInDstToken.rawAmount + watchtowerFee.amountInDstToken.rawAmount,
438
+ this.wrapper.tokens[this.getSwapData().getToken()], this.wrapper.prices, this.pricingInfo
439
+ ),
440
+ currentUsdValue: amountInSrcToken.currentUsdValue,
441
+ usdValue: amountInSrcToken.usdValue,
442
+ pastUsdValue: amountInSrcToken.pastUsdValue
443
+ };
444
+ }
445
+
446
+ getFeeBreakdown(): [
447
+ {type: FeeType.SWAP, fee: Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>>},
448
+ {type: FeeType.NETWORK_OUTPUT, fee: Fee<T["ChainId"], BtcToken<true>, SCToken<T["ChainId"]>>}
449
+ ] {
450
+ return [
451
+ {
452
+ type: FeeType.SWAP,
453
+ fee: this.getSwapFee()
454
+ },
455
+ {
456
+ type: FeeType.NETWORK_OUTPUT,
457
+ fee: this.getWatchtowerFee()
458
+ }
459
+ ];
460
+ }
461
+
462
+
463
+ //////////////////////////////
464
+ //// Execution
465
+
466
+ /**
467
+ * Executes the swap with the provided bitcoin lightning network wallet or LNURL
468
+ *
469
+ * @param walletOrLnurlWithdraw Bitcoin lightning wallet to use to pay the lightning network invoice, or an LNURL-withdraw
470
+ * link, wallet is not required and the LN invoice can be paid externally as well (just pass null or undefined here)
471
+ * @param callbacks Callbacks to track the progress of the swap
472
+ * @param options Optional options for the swap like feeRate, AbortSignal, and timeouts/intervals
473
+ *
474
+ * @returns {boolean} Whether a swap was settled automatically by swap watchtowers or requires manual claim by the
475
+ * user, in case `false` is returned the user should call `swap.claim()` to settle the swap on the destination manually
476
+ */
477
+ async execute(
478
+ walletOrLnurlWithdraw?: MinimalLightningNetworkWalletInterface | LNURLWithdraw | string | null | undefined,
479
+ callbacks?: {
480
+ onSourceTransactionReceived?: (sourceTxId: string) => void,
481
+ onSwapSettled?: (destinationTxId: string) => void
482
+ },
483
+ options?: {
484
+ abortSignal?: AbortSignal,
485
+ lightningTxCheckIntervalSeconds?: number,
486
+ maxWaitTillAutomaticSettlementSeconds?: number
487
+ }
488
+ ): Promise<boolean> {
489
+ if(this.state===FromBTCLNAutoSwapState.FAILED) throw new Error("Swap failed!");
490
+ if(this.state===FromBTCLNAutoSwapState.EXPIRED) throw new Error("Swap HTLC expired!");
491
+ if(this.state===FromBTCLNAutoSwapState.QUOTE_EXPIRED || this.state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) throw new Error("Swap quote expired!");
492
+ if(this.state===FromBTCLNAutoSwapState.CLAIM_CLAIMED) throw new Error("Swap already settled!");
493
+
494
+ let abortSignal = options?.abortSignal;
495
+
496
+ if(this.state===FromBTCLNAutoSwapState.PR_CREATED) {
497
+ if(walletOrLnurlWithdraw!=null && this.lnurl==null) {
498
+ if(typeof(walletOrLnurlWithdraw)==="string" || isLNURLWithdraw(walletOrLnurlWithdraw)) {
499
+ await this.settleWithLNURLWithdraw(walletOrLnurlWithdraw);
500
+ } else {
501
+ const paymentPromise = walletOrLnurlWithdraw.payInvoice(this.pr);
502
+
503
+ const abortController = new AbortController();
504
+ paymentPromise.catch(e => abortController.abort(e));
505
+ if(options?.abortSignal!=null) options.abortSignal.addEventListener("abort", () => abortController.abort(options?.abortSignal?.reason));
506
+ abortSignal = abortController.signal;
507
+ }
508
+ }
509
+ }
510
+
511
+ if(this.state===FromBTCLNAutoSwapState.PR_CREATED || this.state===FromBTCLNAutoSwapState.PR_PAID) {
512
+ const paymentSuccess = await this.waitForPayment(callbacks?.onSourceTransactionReceived, options?.lightningTxCheckIntervalSeconds, abortSignal);
513
+ if (!paymentSuccess) throw new Error("Failed to receive lightning network payment");
514
+ }
515
+
516
+ if((this.state as FromBTCLNAutoSwapState)===FromBTCLNAutoSwapState.CLAIM_CLAIMED) return true;
517
+
518
+ if(this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED) {
519
+ const success = await this.waitTillClaimed(options?.maxWaitTillAutomaticSettlementSeconds ?? 60, options?.abortSignal);
520
+ if (success && callbacks?.onSwapSettled != null) callbacks.onSwapSettled(this.getOutputTxId()!);
521
+ return success;
522
+ }
523
+
524
+ throw new Error("Invalid state reached!");
525
+ }
526
+
527
+ async txsExecute() {
528
+ if (this.state === FromBTCLNAutoSwapState.PR_CREATED) {
529
+ if (!await this.verifyQuoteValid()) throw new Error("Quote already expired or close to expiry!");
530
+ return [
531
+ {
532
+ name: "Payment" as const,
533
+ description: "Initiates the swap by paying up the lightning network invoice",
534
+ chain: "LIGHTNING",
535
+ txs: [
536
+ {
537
+ address: this.pr,
538
+ hyperlink: this.getHyperlink()
539
+ }
540
+ ]
541
+ }
542
+ ];
543
+ }
544
+
545
+ throw new Error("Invalid swap state to obtain execution txns, required PR_CREATED");
546
+ }
547
+
548
+
549
+ //////////////////////////////
550
+ //// Payment
551
+
552
+ /**
553
+ * Checks whether the LP received the LN payment and we can continue by committing & claiming the HTLC on-chain
554
+ *
555
+ * @param save If the new swap state should be saved
556
+ */
557
+ async _checkIntermediaryPaymentReceived(save: boolean = true): Promise<boolean | null> {
558
+ if(
559
+ this.state===FromBTCLNAutoSwapState.PR_PAID ||
560
+ this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED ||
561
+ this.state===FromBTCLNAutoSwapState.CLAIM_CLAIMED ||
562
+ this.state===FromBTCLNAutoSwapState.FAILED
563
+ ) return true;
564
+ if(this.state===FromBTCLNAutoSwapState.QUOTE_EXPIRED) return false;
565
+ if(this.url==null) return false;
566
+ const resp = await IntermediaryAPI.getInvoiceStatus(this.url, this.getPaymentHash().toString("hex"));
567
+ switch(resp.code) {
568
+ case InvoiceStatusResponseCodes.PAID:
569
+ const data = new this.wrapper.swapDataDeserializer(resp.data.data);
570
+ if(this.state===FromBTCLNAutoSwapState.PR_CREATED || this.state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) try {
571
+ await this._saveRealSwapData(data, save);
572
+ return true;
573
+ } catch (e) {}
574
+ return null;
575
+ case InvoiceStatusResponseCodes.EXPIRED:
576
+ this.state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
577
+ this.initiated = true;
578
+ if(save) await this._saveAndEmit();
579
+ return false;
580
+ default:
581
+ return null;
582
+ }
583
+ }
584
+
585
+ async _saveRealSwapData(data: T["Data"], save?: boolean): Promise<boolean> {
586
+ await this.checkIntermediaryReturnedData(data);
587
+ if(this.state===FromBTCLNAutoSwapState.PR_CREATED || this.state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
588
+ this.state = FromBTCLNAutoSwapState.PR_PAID;
589
+ this.data = data;
590
+ this.initiated = true;
591
+ if(save) await this._saveAndEmit();
592
+ return true;
593
+ }
594
+ return false;
595
+ }
596
+
597
+ /**
598
+ * Checks the data returned by the intermediary in the payment auth request
599
+ *
600
+ * @param data Parsed swap data as returned by the intermediary
601
+ * @protected
602
+ * @throws {IntermediaryError} If the returned are not valid
603
+ * @throws {Error} If the swap is already committed on-chain
604
+ */
605
+ protected async checkIntermediaryReturnedData(data: T["Data"]): Promise<void> {
606
+ if (!data.isPayOut()) throw new IntermediaryError("Invalid not pay out");
607
+ if (data.getType() !== ChainSwapType.HTLC) throw new IntermediaryError("Invalid swap type");
608
+ if (!data.isOfferer(this.getSwapData().getOfferer())) throw new IntermediaryError("Invalid offerer used");
609
+ if (!data.isClaimer(this._getInitiator())) throw new IntermediaryError("Invalid claimer used");
610
+ if (!data.isToken(this.getSwapData().getToken())) throw new IntermediaryError("Invalid token used");
611
+ if (data.getSecurityDeposit() !== this.getSwapData().getSecurityDeposit()) throw new IntermediaryError("Invalid security deposit!");
612
+ if (data.getClaimerBounty() !== this.getSwapData().getClaimerBounty()) throw new IntermediaryError("Invalid security deposit!");
613
+ if (data.getAmount() < this.getSwapData().getAmount()) throw new IntermediaryError("Invalid amount received!");
614
+ if (data.getClaimHash() !== this.getSwapData().getClaimHash()) throw new IntermediaryError("Invalid payment hash used!");
615
+ if (!data.isDepositToken(this.getSwapData().getDepositToken())) throw new IntermediaryError("Invalid deposit token used!");
616
+ if (data.hasSuccessAction()) throw new IntermediaryError("Invalid has success action");
617
+
618
+ if (await this.wrapper.contract.isExpired(this._getInitiator(), data)) throw new IntermediaryError("Not enough time to claim!");
619
+ if (this.wrapper.getHtlcTimeout(data) <= (Date.now()/1000)) throw new IntermediaryError("HTLC expires too soon!");
620
+ }
621
+
622
+ /**
623
+ * Waits till an LN payment is received by the intermediary and client can continue commiting & claiming the HTLC
624
+ *
625
+ * @param onPaymentReceived Callback as for when the LP reports having received the ln payment
626
+ * @param checkIntervalSeconds How often to poll the intermediary for answer (default 5 seconds)
627
+ * @param abortSignal Abort signal to stop waiting for payment
628
+ */
629
+ async waitForPayment(onPaymentReceived?: (txId: string) => void, checkIntervalSeconds?: number, abortSignal?: AbortSignal): Promise<boolean> {
630
+ checkIntervalSeconds ??= 5;
631
+ if(this.state===FromBTCLNAutoSwapState.PR_PAID) {
632
+ await this.waitTillCommited(checkIntervalSeconds, abortSignal);
633
+ }
634
+ if(this.state>=FromBTCLNAutoSwapState.CLAIM_COMMITED) return true;
635
+ if(
636
+ this.state!==FromBTCLNAutoSwapState.PR_CREATED
637
+ ) throw new Error("Must be in PR_CREATED state!");
638
+
639
+ const abortController = new AbortController();
640
+ if(abortSignal!=null) abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
641
+
642
+ let save = false;
643
+
644
+ if(this.lnurl!=null && this.lnurlK1!=null && this.lnurlCallback!=null && !this.prPosted) {
645
+ LNURL.postInvoiceToLNURLWithdraw({k1: this.lnurlK1, callback: this.lnurlCallback}, this.pr).catch(e => {
646
+ this.lnurlFailSignal.abort(e);
647
+ });
648
+ this.prPosted = true;
649
+ save ||= true;
650
+ }
651
+
652
+ if(!this.initiated) {
653
+ this.initiated = true;
654
+ save ||= true;
655
+ }
656
+
657
+ if(save) await this._saveAndEmit();
658
+
659
+ let lnurlFailListener = () => abortController.abort(this.lnurlFailSignal.signal.reason);
660
+ this.lnurlFailSignal.signal.addEventListener("abort", lnurlFailListener);
661
+ this.lnurlFailSignal.signal.throwIfAborted();
662
+
663
+ if(this.wrapper.messenger.warmup!=null) await this.wrapper.messenger.warmup().catch(e => {
664
+ this.logger.warn("waitForPayment(): Failed to warmup messenger: ", e);
665
+ });
666
+
667
+ if(this.state===FromBTCLNAutoSwapState.PR_CREATED) {
668
+ const promises: Promise<boolean | undefined>[] = [
669
+ this.waitTillState(FromBTCLNAutoSwapState.PR_PAID, "gte", abortController.signal).then(() => true)
670
+ ];
671
+ if(this.url!=null) promises.push((async () => {
672
+ let resp: InvoiceStatusResponse = {code: InvoiceStatusResponseCodes.PENDING, msg: ""};
673
+ while(!abortController.signal.aborted && resp.code===InvoiceStatusResponseCodes.PENDING) {
674
+ resp = await IntermediaryAPI.getInvoiceStatus(this.url!, this.getPaymentHash().toString("hex"));
675
+ if(resp.code===InvoiceStatusResponseCodes.PENDING)
676
+ await timeoutPromise(checkIntervalSeconds*1000, abortController.signal);
677
+ }
678
+ this.lnurlFailSignal.signal.removeEventListener("abort", lnurlFailListener);
679
+ abortController.signal.throwIfAborted();
680
+
681
+ if(resp.code===InvoiceStatusResponseCodes.PAID) {
682
+ const swapData = new this.wrapper.swapDataDeserializer(resp.data.data);
683
+ return await this._saveRealSwapData(swapData, true);
684
+ }
685
+
686
+ if(this.state===FromBTCLNAutoSwapState.PR_CREATED || this.state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
687
+ if(resp.code===InvoiceStatusResponseCodes.EXPIRED) {
688
+ await this._saveAndEmit(FromBTCLNAutoSwapState.QUOTE_EXPIRED);
689
+ }
690
+ return false;
691
+ }
692
+ })());
693
+ const paymentResult = await Promise.race(promises);
694
+ abortController.abort();
695
+
696
+ if(!paymentResult) return false;
697
+ if(onPaymentReceived!=null) onPaymentReceived(this.getInputTxId());
698
+ }
699
+
700
+ if((this.state as FromBTCLNAutoSwapState)===FromBTCLNAutoSwapState.PR_PAID) {
701
+ await this.waitTillCommited(checkIntervalSeconds, abortSignal);
702
+ }
703
+
704
+ return this.state>=FromBTCLNAutoSwapState.CLAIM_COMMITED;
705
+ }
706
+
707
+
708
+ //////////////////////////////
709
+ //// Commit
710
+
711
+ protected async waitTillCommited(checkIntervalSeconds?: number, abortSignal?: AbortSignal): Promise<void> {
712
+ if(this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED || this.state===FromBTCLNAutoSwapState.CLAIM_CLAIMED) return Promise.resolve();
713
+ if(this.state!==FromBTCLNAutoSwapState.PR_PAID) throw new Error("Invalid state");
714
+
715
+ const abortController = extendAbortController(abortSignal);
716
+ let result: number | boolean;
717
+ try {
718
+ result = await Promise.race([
719
+ this.watchdogWaitTillCommited(checkIntervalSeconds, abortController.signal),
720
+ this.waitTillState(FromBTCLNAutoSwapState.CLAIM_COMMITED, "gte", abortController.signal).then(() => 0)
721
+ ]);
722
+ abortController.abort();
723
+ } catch (e) {
724
+ abortController.abort();
725
+ throw e;
726
+ }
727
+
728
+ if(result===false) {
729
+ this.logger.debug("waitTillCommited(): Resolved from watchdog - HTLC expired");
730
+ if(
731
+ this.state===FromBTCLNAutoSwapState.PR_PAID
732
+ ) {
733
+ await this._saveAndEmit(FromBTCLNAutoSwapState.EXPIRED);
734
+ }
735
+ return;
736
+ }
737
+
738
+ if(
739
+ this.state===FromBTCLNAutoSwapState.PR_PAID
740
+ ) {
741
+ await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_COMMITED);
742
+ }
743
+
744
+ if(result===0) this.logger.debug("waitTillCommited(): Resolved from state changed");
745
+ if(result===true) {
746
+ this.logger.debug("waitTillCommited(): Resolved from watchdog - commited");
747
+ await this._broadcastSecret().catch(e => {
748
+ this.logger.error("waitTillCommited(): Error broadcasting swap secret: ", e);
749
+ });
750
+ }
751
+ }
752
+
753
+
754
+ //////////////////////////////
755
+ //// Claim
756
+
757
+ /**
758
+ * Returns transactions required for claiming the HTLC and finishing the swap by revealing the HTLC secret
759
+ * (hash preimage)
760
+ *
761
+ * @param _signer Optional signer address to use for claiming the swap, can also be different from the initializer
762
+ * @throws {Error} If in invalid state (must be CLAIM_COMMITED)
763
+ */
764
+ async txsClaim(_signer?: T["Signer"] | T["NativeSigner"]): Promise<T["TX"][]> {
765
+ if(this.state!==FromBTCLNAutoSwapState.CLAIM_COMMITED) throw new Error("Must be in CLAIM_COMMITED state!");
766
+ if(this.data==null) throw new Error("Unknown data, wrong state?");
767
+
768
+ return await this.wrapper.contract.txsClaimWithSecret(
769
+ _signer==null ?
770
+ this._getInitiator() :
771
+ (isAbstractSigner(_signer) ? _signer : await this.wrapper.chain.wrapSigner(_signer)),
772
+ this.data, this.secret, true, true
773
+ );
774
+ }
775
+
776
+ /**
777
+ * Claims and finishes the swap
778
+ *
779
+ * @param _signer Signer to sign the transactions with, can also be different to the initializer
780
+ * @param abortSignal Abort signal to stop waiting for transaction confirmation
781
+ */
782
+ async claim(_signer: T["Signer"] | T["NativeSigner"], abortSignal?: AbortSignal): Promise<string> {
783
+ const signer = isAbstractSigner(_signer) ? _signer : await this.wrapper.chain.wrapSigner(_signer);
784
+ const result = await this.wrapper.chain.sendAndConfirm(
785
+ signer, await this.txsClaim(), true, abortSignal
786
+ );
787
+
788
+ this.claimTxId = result[0];
789
+ if(this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED || this.state===FromBTCLNAutoSwapState.EXPIRED || this.state===FromBTCLNAutoSwapState.FAILED) {
790
+ await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_CLAIMED);
791
+ }
792
+ return result[0];
793
+ }
794
+
795
+ /**
796
+ * Waits till the swap is successfully claimed
797
+ *
798
+ * @param maxWaitTimeSeconds Maximum time in seconds to wait for the swap to be settled
799
+ * @param abortSignal AbortSignal
800
+ * @throws {Error} If swap is in invalid state (must be BTC_TX_CONFIRMED)
801
+ * @throws {Error} If the LP refunded sooner than we were able to claim
802
+ * @returns {boolean} whether the swap was claimed in time or not
803
+ */
804
+ async waitTillClaimed(maxWaitTimeSeconds?: number, abortSignal?: AbortSignal): Promise<boolean> {
805
+ if(this.state===FromBTCLNAutoSwapState.CLAIM_CLAIMED) return Promise.resolve(true);
806
+ if(this.state!==FromBTCLNAutoSwapState.CLAIM_COMMITED) throw new Error("Invalid state (not CLAIM_COMMITED)");
807
+
808
+ const abortController = new AbortController();
809
+ if(abortSignal!=null) abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
810
+ let timedOut: boolean = false;
811
+ if(maxWaitTimeSeconds!=null) {
812
+ const timeout = setTimeout(() => {
813
+ timedOut = true;
814
+ abortController.abort();
815
+ }, maxWaitTimeSeconds * 1000);
816
+ abortController.signal.addEventListener("abort", () => clearTimeout(timeout));
817
+ }
818
+
819
+ let res: 0 | 1 | SwapCommitState;
820
+ try {
821
+ res = await Promise.race([
822
+ this.watchdogWaitTillResult(undefined, abortController.signal),
823
+ this.waitTillState(FromBTCLNAutoSwapState.CLAIM_CLAIMED, "eq", abortController.signal).then(() => 0 as const),
824
+ this.waitTillState(FromBTCLNAutoSwapState.EXPIRED, "eq", abortController.signal).then(() => 1 as const),
825
+ ]);
826
+ abortController.abort();
827
+ } catch (e) {
828
+ abortController.abort();
829
+ if(timedOut) return false;
830
+ throw e;
831
+ }
832
+
833
+ if(res===0) {
834
+ this.logger.debug("waitTillClaimed(): Resolved from state change (CLAIM_CLAIMED)");
835
+ return true;
836
+ }
837
+ if(res===1) {
838
+ this.logger.debug("waitTillClaimed(): Resolved from state change (EXPIRED)");
839
+ throw new Error("Swap expired during claiming");
840
+ }
841
+ this.logger.debug("waitTillClaimed(): Resolved from watchdog");
842
+
843
+ if(res?.type===SwapCommitStateType.PAID) {
844
+ if((this.state as FromBTCLNAutoSwapState)!==FromBTCLNAutoSwapState.CLAIM_CLAIMED) {
845
+ this.claimTxId = await res.getClaimTxId();
846
+ await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_CLAIMED);
847
+ }
848
+ }
849
+ if(res?.type===SwapCommitStateType.NOT_COMMITED || res?.type===SwapCommitStateType.EXPIRED) {
850
+ if(
851
+ (this.state as FromBTCLNAutoSwapState)!==FromBTCLNAutoSwapState.CLAIM_CLAIMED &&
852
+ (this.state as FromBTCLNAutoSwapState)!==FromBTCLNAutoSwapState.FAILED
853
+ ) {
854
+ await this._saveAndEmit(FromBTCLNAutoSwapState.FAILED);
855
+ }
856
+ throw new Error("Swap expired during claiming");
857
+ }
858
+ return true;
859
+ }
860
+
861
+
862
+ //////////////////////////////
863
+ //// LNURL
864
+
865
+ /**
866
+ * Is this an LNURL-withdraw swap?
867
+ */
868
+ isLNURL(): boolean {
869
+ return this.lnurl!=null;
870
+ }
871
+
872
+ /**
873
+ * Gets the used LNURL or null if this is not an LNURL-withdraw swap
874
+ */
875
+ getLNURL(): string | null {
876
+ return this.lnurl ?? null;
877
+ }
878
+
879
+ /**
880
+ * Pay the generated lightning network invoice with LNURL-withdraw
881
+ */
882
+ async settleWithLNURLWithdraw(lnurl: string | LNURLWithdraw): Promise<void> {
883
+ if(this.lnurl!=null) throw new Error("Cannot settle LNURL-withdraw swap with different LNURL");
884
+ let lnurlParams: LNURLWithdrawParamsWithUrl;
885
+ if(typeof(lnurl)==="string") {
886
+ const parsedLNURL = await LNURL.getLNURL(lnurl);
887
+ if(parsedLNURL==null || parsedLNURL.tag!=="withdrawRequest")
888
+ throw new UserError("Invalid LNURL-withdraw to settle the swap");
889
+ lnurlParams = parsedLNURL;
890
+ } else {
891
+ lnurlParams = lnurl.params;
892
+ }
893
+ LNURL.useLNURLWithdraw(lnurlParams, this.pr).catch(e => this.lnurlFailSignal.abort(e));
894
+ this.lnurl = lnurlParams.url;
895
+ this.lnurlCallback = lnurlParams.callback;
896
+ this.lnurlK1 = lnurlParams.k1;
897
+ this.prPosted = true;
898
+ await this._saveAndEmit();
899
+ }
900
+
901
+
902
+ //////////////////////////////
903
+ //// Storage
904
+
905
+ serialize(): any {
906
+ return {
907
+ ...super.serialize(),
908
+ data: this.data==null ? null : this.data.serialize(),
909
+ commitTxId: this.commitTxId,
910
+ claimTxId: this.claimTxId,
911
+ btcAmountSwap: this.btcAmountSwap==null ? null : this.btcAmountSwap.toString(10),
912
+ btcAmountGas: this.btcAmountGas==null ? null : this.btcAmountGas.toString(10),
913
+ gasSwapFeeBtc: this.gasSwapFeeBtc==null ? null : this.gasSwapFeeBtc.toString(10),
914
+ gasSwapFee: this.gasSwapFee==null ? null : this.gasSwapFee.toString(10),
915
+ gasPricingInfo: serializePriceInfoType(this.gasPricingInfo),
916
+ pr: this.pr,
917
+ secret: this.secret,
918
+ lnurl: this.lnurl,
919
+ lnurlK1: this.lnurlK1,
920
+ lnurlCallback: this.lnurlCallback,
921
+ prPosted: this.prPosted,
922
+ initialSwapData: this.initialSwapData.serialize()
923
+ };
924
+ }
925
+
926
+
927
+ //////////////////////////////
928
+ //// Swap ticks & sync
929
+
930
+ /**
931
+ * Checks the swap's state on-chain and compares it to its internal state, updates/changes it according to on-chain
932
+ * data
933
+ *
934
+ * @private
935
+ */
936
+ private async syncStateFromChain(quoteDefinitelyExpired?: boolean, commitStatus?: SwapCommitState): Promise<boolean> {
937
+ //Check for expiry before the getCommitStatus to prevent race conditions
938
+ let quoteExpired: boolean = false;
939
+ if(this.state===FromBTCLNAutoSwapState.PR_PAID) {
940
+ quoteExpired = quoteDefinitelyExpired ?? await this._verifyQuoteDefinitelyExpired();
941
+ }
942
+
943
+ if(this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED || this.state===FromBTCLNAutoSwapState.EXPIRED) {
944
+ //Check if it's already successfully paid
945
+ commitStatus ??= await this.wrapper.contract.getCommitStatus(this._getInitiator(), this.data!);
946
+ if(commitStatus?.type===SwapCommitStateType.PAID) {
947
+ if(this.claimTxId==null) this.claimTxId = await commitStatus.getClaimTxId();
948
+ this.state = FromBTCLNAutoSwapState.CLAIM_CLAIMED;
949
+ return true;
950
+ }
951
+
952
+ if(commitStatus?.type===SwapCommitStateType.NOT_COMMITED || commitStatus?.type===SwapCommitStateType.EXPIRED) {
953
+ this.state = FromBTCLNAutoSwapState.FAILED;
954
+ return true;
955
+ }
956
+ }
957
+
958
+ if(this.state===FromBTCLNAutoSwapState.PR_PAID) {
959
+ //Check if it's already committed
960
+ commitStatus ??= await this.wrapper.contract.getCommitStatus(this._getInitiator(), this.data!);
961
+ switch(commitStatus?.type) {
962
+ case SwapCommitStateType.COMMITED:
963
+ this.state = FromBTCLNAutoSwapState.CLAIM_COMMITED;
964
+ return true;
965
+ case SwapCommitStateType.EXPIRED:
966
+ this.state = FromBTCLNAutoSwapState.EXPIRED;
967
+ return true;
968
+ case SwapCommitStateType.PAID:
969
+ if(this.claimTxId==null) this.claimTxId = await commitStatus.getClaimTxId();
970
+ this.state = FromBTCLNAutoSwapState.CLAIM_CLAIMED;
971
+ return true;
972
+ }
973
+ if(quoteExpired) {
974
+ this.state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
975
+ return true;
976
+ }
977
+ }
978
+
979
+ return false;
980
+ }
981
+
982
+ _shouldFetchCommitStatus(): boolean {
983
+ return this.state===FromBTCLNAutoSwapState.PR_PAID || this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED || this.state===FromBTCLNAutoSwapState.EXPIRED;
984
+ }
985
+
986
+ _shouldFetchExpiryStatus(): boolean {
987
+ return this.state===FromBTCLNAutoSwapState.PR_PAID;
988
+ }
989
+
990
+ _shouldCheckIntermediary(): boolean {
991
+ return this.state===FromBTCLNAutoSwapState.PR_CREATED || this.state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
992
+ }
993
+
994
+ async _sync(save?: boolean, quoteDefinitelyExpired?: boolean, commitStatus?: SwapCommitState, skipLpCheck?: boolean): Promise<boolean> {
995
+ let changed = false;
996
+
997
+ if(this.state===FromBTCLNAutoSwapState.PR_CREATED || this.state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
998
+ if(this.state!==FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED && this.getQuoteExpiry()<Date.now()) {
999
+ this.state = FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1000
+ changed ||= true;
1001
+ }
1002
+
1003
+ if(!skipLpCheck) try {
1004
+ const result = await this._checkIntermediaryPaymentReceived(false);
1005
+ if (result !== null) changed ||= true;
1006
+ } catch(e) {
1007
+ this.logger.error("_sync(): Failed to synchronize swap, error: ", e);
1008
+ }
1009
+
1010
+ if(this.state===FromBTCLNAutoSwapState.PR_CREATED || this.state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
1011
+ if(await this._verifyQuoteDefinitelyExpired()) {
1012
+ this.state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1013
+ changed ||= true;
1014
+ }
1015
+ }
1016
+ }
1017
+
1018
+ if(await this.syncStateFromChain(quoteDefinitelyExpired, commitStatus)) changed = true;
1019
+
1020
+ if(save && changed) await this._saveAndEmit();
1021
+
1022
+ if(this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED) await this._broadcastSecret().catch(e => {
1023
+ this.logger.error("_sync(): Error when broadcasting swap secret: ", e);
1024
+ });
1025
+
1026
+ return changed;
1027
+ }
1028
+
1029
+ private broadcastTickCounter: number = 0;
1030
+
1031
+ async _broadcastSecret(noCheckExpiry?: boolean): Promise<void> {
1032
+ if(this.state!==FromBTCLNAutoSwapState.CLAIM_COMMITED) throw new Error("Must be in CLAIM_COMMITED state to broadcast swap secret!");
1033
+ if(this.data==null) throw new Error("Unknown data, wrong state?");
1034
+
1035
+ if(!noCheckExpiry) {
1036
+ if(await this.wrapper.contract.isExpired(this._getInitiator(), this.data)) throw new Error("On-chain HTLC already expired!");
1037
+ }
1038
+ await this.wrapper.messenger.broadcast(new SwapClaimWitnessMessage(this.data, this.secret));
1039
+ }
1040
+
1041
+ async _tick(save?: boolean): Promise<boolean> {
1042
+ switch(this.state) {
1043
+ case FromBTCLNAutoSwapState.PR_CREATED:
1044
+ if(this.getQuoteExpiry() < Date.now()) {
1045
+ this.state = FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1046
+ if(save) await this._saveAndEmit();
1047
+ return true;
1048
+ }
1049
+ break;
1050
+ case FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED:
1051
+ if(this.getDefinitiveExpiryTime() < Date.now()) {
1052
+ this.state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1053
+ if(save) await this._saveAndEmit();
1054
+ return true;
1055
+ }
1056
+ break;
1057
+ case FromBTCLNAutoSwapState.PR_PAID:
1058
+ case FromBTCLNAutoSwapState.CLAIM_COMMITED:
1059
+ const expired = await this.wrapper.contract.isExpired(this._getInitiator(), this.data!);
1060
+ if(expired) {
1061
+ this.state = FromBTCLNAutoSwapState.EXPIRED;
1062
+ if(save) await this._saveAndEmit();
1063
+ return true;
1064
+ }
1065
+ if(this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED) {
1066
+ //Broadcast the secret over the provided messenger channel
1067
+ if(this.broadcastTickCounter===0) await this._broadcastSecret(true).catch(e => {
1068
+ this.logger.warn("_tick(): Error when broadcasting swap secret: ", e);
1069
+ });
1070
+ this.broadcastTickCounter = (this.broadcastTickCounter + 1) % 3; //Broadcast every 3rd tick
1071
+ }
1072
+ break;
1073
+ }
1074
+
1075
+ return false;
1076
+ }
1077
+
1078
+ }