@atomiqlabs/sdk 8.6.6 → 8.6.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 (225) hide show
  1. package/dist/SmartChainAssets.d.ts +181 -181
  2. package/dist/SmartChainAssets.js +181 -181
  3. package/dist/bitcoin/coinselect2/accumulative.d.ts +6 -6
  4. package/dist/bitcoin/coinselect2/accumulative.js +52 -51
  5. package/dist/bitcoin/coinselect2/blackjack.d.ts +6 -6
  6. package/dist/bitcoin/coinselect2/blackjack.js +38 -37
  7. package/dist/bitcoin/coinselect2/index.d.ts +19 -17
  8. package/dist/bitcoin/coinselect2/index.js +69 -69
  9. package/dist/bitcoin/coinselect2/utils.d.ts +77 -75
  10. package/dist/bitcoin/coinselect2/utils.js +123 -123
  11. package/dist/bitcoin/wallet/BitcoinWallet.d.ts +130 -128
  12. package/dist/bitcoin/wallet/BitcoinWallet.js +322 -322
  13. package/dist/bitcoin/wallet/IBitcoinWallet.d.ts +78 -78
  14. package/dist/bitcoin/wallet/IBitcoinWallet.js +21 -20
  15. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.d.ts +101 -99
  16. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.js +176 -176
  17. package/dist/enums/FeeType.d.ts +15 -15
  18. package/dist/enums/FeeType.js +19 -19
  19. package/dist/enums/SwapAmountType.d.ts +15 -15
  20. package/dist/enums/SwapAmountType.js +19 -19
  21. package/dist/enums/SwapDirection.d.ts +15 -15
  22. package/dist/enums/SwapDirection.js +19 -19
  23. package/dist/enums/SwapSide.d.ts +15 -15
  24. package/dist/enums/SwapSide.js +19 -19
  25. package/dist/enums/SwapType.d.ts +75 -75
  26. package/dist/enums/SwapType.js +79 -79
  27. package/dist/errors/IntermediaryError.d.ts +13 -13
  28. package/dist/errors/IntermediaryError.js +27 -27
  29. package/dist/errors/RequestError.d.ts +32 -32
  30. package/dist/errors/RequestError.js +54 -54
  31. package/dist/errors/UserError.d.ts +8 -8
  32. package/dist/errors/UserError.js +16 -16
  33. package/dist/events/UnifiedSwapEventListener.d.ts +23 -23
  34. package/dist/events/UnifiedSwapEventListener.js +130 -130
  35. package/dist/http/HttpUtils.d.ts +27 -27
  36. package/dist/http/HttpUtils.js +91 -90
  37. package/dist/http/paramcoders/IParamReader.d.ts +8 -8
  38. package/dist/http/paramcoders/IParamReader.js +2 -2
  39. package/dist/http/paramcoders/ParamDecoder.d.ts +44 -42
  40. package/dist/http/paramcoders/ParamDecoder.js +137 -137
  41. package/dist/http/paramcoders/ParamEncoder.d.ts +20 -18
  42. package/dist/http/paramcoders/ParamEncoder.js +36 -36
  43. package/dist/http/paramcoders/SchemaVerifier.d.ts +26 -26
  44. package/dist/http/paramcoders/SchemaVerifier.js +145 -145
  45. package/dist/http/paramcoders/client/ResponseParamDecoder.d.ts +11 -11
  46. package/dist/http/paramcoders/client/ResponseParamDecoder.js +57 -57
  47. package/dist/http/paramcoders/client/StreamParamEncoder.d.ts +13 -11
  48. package/dist/http/paramcoders/client/StreamParamEncoder.js +26 -26
  49. package/dist/http/paramcoders/client/StreamingFetchPromise.d.ts +16 -16
  50. package/dist/http/paramcoders/client/StreamingFetchPromise.js +174 -173
  51. package/dist/index.d.ts +85 -85
  52. package/dist/index.js +158 -158
  53. package/dist/intermediaries/Intermediary.d.ts +157 -157
  54. package/dist/intermediaries/Intermediary.js +142 -142
  55. package/dist/intermediaries/IntermediaryDiscovery.d.ts +199 -198
  56. package/dist/intermediaries/IntermediaryDiscovery.js +406 -406
  57. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +439 -437
  58. package/dist/intermediaries/apis/IntermediaryAPI.js +603 -603
  59. package/dist/intermediaries/apis/TrustedIntermediaryAPI.d.ts +155 -155
  60. package/dist/intermediaries/apis/TrustedIntermediaryAPI.js +137 -137
  61. package/dist/lnurl/LNURL.d.ts +102 -102
  62. package/dist/lnurl/LNURL.js +321 -321
  63. package/dist/prices/RedundantSwapPrice.d.ts +110 -110
  64. package/dist/prices/RedundantSwapPrice.js +222 -222
  65. package/dist/prices/SingleSwapPrice.d.ts +34 -34
  66. package/dist/prices/SingleSwapPrice.js +44 -44
  67. package/dist/prices/SwapPriceWithChain.d.ts +107 -107
  68. package/dist/prices/SwapPriceWithChain.js +128 -128
  69. package/dist/prices/abstract/ICachedSwapPrice.d.ts +28 -28
  70. package/dist/prices/abstract/ICachedSwapPrice.js +62 -62
  71. package/dist/prices/abstract/IPriceProvider.d.ts +81 -81
  72. package/dist/prices/abstract/IPriceProvider.js +74 -74
  73. package/dist/prices/abstract/ISwapPrice.d.ts +168 -168
  74. package/dist/prices/abstract/ISwapPrice.js +279 -279
  75. package/dist/prices/providers/BinancePriceProvider.d.ts +23 -23
  76. package/dist/prices/providers/BinancePriceProvider.js +30 -30
  77. package/dist/prices/providers/CoinGeckoPriceProvider.d.ts +23 -23
  78. package/dist/prices/providers/CoinGeckoPriceProvider.js +29 -29
  79. package/dist/prices/providers/CoinPaprikaPriceProvider.d.ts +25 -25
  80. package/dist/prices/providers/CoinPaprikaPriceProvider.js +29 -29
  81. package/dist/prices/providers/CustomPriceProvider.d.ts +24 -24
  82. package/dist/prices/providers/CustomPriceProvider.js +35 -35
  83. package/dist/prices/providers/KrakenPriceProvider.d.ts +38 -38
  84. package/dist/prices/providers/KrakenPriceProvider.js +45 -45
  85. package/dist/prices/providers/OKXPriceProvider.d.ts +34 -34
  86. package/dist/prices/providers/OKXPriceProvider.js +29 -29
  87. package/dist/prices/providers/abstract/ExchangePriceProvider.d.ts +17 -17
  88. package/dist/prices/providers/abstract/ExchangePriceProvider.js +21 -21
  89. package/dist/prices/providers/abstract/HttpPriceProvider.d.ts +7 -7
  90. package/dist/prices/providers/abstract/HttpPriceProvider.js +12 -12
  91. package/dist/storage/IUnifiedStorage.d.ts +85 -85
  92. package/dist/storage/IUnifiedStorage.js +2 -2
  93. package/dist/storage/UnifiedSwapStorage.d.ts +114 -114
  94. package/dist/storage/UnifiedSwapStorage.js +116 -116
  95. package/dist/storage-browser/IndexedDBUnifiedStorage.d.ts +63 -63
  96. package/dist/storage-browser/IndexedDBUnifiedStorage.js +298 -298
  97. package/dist/storage-browser/LocalStorageManager.d.ts +49 -49
  98. package/dist/storage-browser/LocalStorageManager.js +93 -93
  99. package/dist/swapper/Swapper.d.ts +687 -686
  100. package/dist/swapper/Swapper.js +1603 -1603
  101. package/dist/swapper/SwapperFactory.d.ts +135 -135
  102. package/dist/swapper/SwapperFactory.js +162 -162
  103. package/dist/swapper/SwapperUtils.d.ts +200 -200
  104. package/dist/swapper/SwapperUtils.js +467 -467
  105. package/dist/swapper/SwapperWithChain.d.ts +404 -404
  106. package/dist/swapper/SwapperWithChain.js +469 -469
  107. package/dist/swapper/SwapperWithSigner.d.ts +322 -322
  108. package/dist/swapper/SwapperWithSigner.js +318 -318
  109. package/dist/swaps/IAddressSwap.d.ts +22 -22
  110. package/dist/swaps/IAddressSwap.js +14 -13
  111. package/dist/swaps/IBTCWalletSwap.d.ts +73 -73
  112. package/dist/swaps/IBTCWalletSwap.js +18 -17
  113. package/dist/swaps/IClaimableSwap.d.ts +49 -49
  114. package/dist/swaps/IClaimableSwap.js +15 -14
  115. package/dist/swaps/IClaimableSwapWrapper.d.ts +15 -15
  116. package/dist/swaps/IClaimableSwapWrapper.js +2 -2
  117. package/dist/swaps/IRefundableSwap.d.ts +43 -43
  118. package/dist/swaps/IRefundableSwap.js +14 -13
  119. package/dist/swaps/ISwap.d.ts +387 -386
  120. package/dist/swaps/ISwap.js +346 -346
  121. package/dist/swaps/ISwapWithGasDrop.d.ts +21 -21
  122. package/dist/swaps/ISwapWithGasDrop.js +12 -11
  123. package/dist/swaps/ISwapWrapper.d.ts +285 -283
  124. package/dist/swaps/ISwapWrapper.js +353 -353
  125. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.d.ts +98 -98
  126. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.js +126 -126
  127. package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +135 -133
  128. package/dist/swaps/escrow_swaps/IEscrowSwap.js +169 -169
  129. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +115 -114
  130. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +134 -134
  131. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +101 -98
  132. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +130 -130
  133. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.d.ts +162 -162
  134. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +190 -190
  135. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.d.ts +58 -58
  136. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.js +78 -78
  137. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +531 -529
  138. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +1285 -1285
  139. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +184 -181
  140. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +418 -418
  141. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +583 -581
  142. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +1371 -1371
  143. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +228 -225
  144. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +506 -506
  145. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +458 -458
  146. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +1126 -1126
  147. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +191 -190
  148. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +378 -378
  149. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +403 -403
  150. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +924 -924
  151. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.d.ts +62 -62
  152. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +112 -112
  153. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.d.ts +127 -125
  154. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.js +256 -256
  155. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +242 -241
  156. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +520 -520
  157. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.d.ts +73 -73
  158. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.js +155 -155
  159. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +128 -127
  160. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +278 -278
  161. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +630 -630
  162. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +1443 -1443
  163. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +214 -213
  164. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +756 -756
  165. package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +261 -261
  166. package/dist/swaps/trusted/ln/LnForGasSwap.js +511 -511
  167. package/dist/swaps/trusted/ln/LnForGasWrapper.d.ts +40 -40
  168. package/dist/swaps/trusted/ln/LnForGasWrapper.js +82 -82
  169. package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +342 -342
  170. package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +715 -715
  171. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.d.ts +69 -68
  172. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +92 -92
  173. package/dist/types/AmountData.d.ts +10 -10
  174. package/dist/types/AmountData.js +2 -2
  175. package/dist/types/CustomPriceFunction.d.ts +11 -11
  176. package/dist/types/CustomPriceFunction.js +2 -2
  177. package/dist/types/PriceInfoType.d.ts +28 -28
  178. package/dist/types/PriceInfoType.js +57 -56
  179. package/dist/types/SwapExecutionAction.d.ts +88 -88
  180. package/dist/types/SwapExecutionAction.js +2 -2
  181. package/dist/types/SwapStateInfo.d.ts +5 -5
  182. package/dist/types/SwapStateInfo.js +2 -2
  183. package/dist/types/SwapWithSigner.d.ts +17 -17
  184. package/dist/types/SwapWithSigner.js +43 -42
  185. package/dist/types/Token.d.ts +99 -99
  186. package/dist/types/Token.js +76 -76
  187. package/dist/types/TokenAmount.d.ts +69 -69
  188. package/dist/types/TokenAmount.js +60 -59
  189. package/dist/types/fees/Fee.d.ts +50 -50
  190. package/dist/types/fees/Fee.js +2 -2
  191. package/dist/types/fees/FeeBreakdown.d.ts +11 -11
  192. package/dist/types/fees/FeeBreakdown.js +2 -2
  193. package/dist/types/fees/PercentagePPM.d.ts +17 -17
  194. package/dist/types/fees/PercentagePPM.js +18 -17
  195. package/dist/types/lnurl/LNURLPay.d.ts +61 -61
  196. package/dist/types/lnurl/LNURLPay.js +31 -30
  197. package/dist/types/lnurl/LNURLWithdraw.d.ts +48 -48
  198. package/dist/types/lnurl/LNURLWithdraw.js +27 -26
  199. package/dist/types/wallets/LightningInvoiceCreateService.d.ts +24 -24
  200. package/dist/types/wallets/LightningInvoiceCreateService.js +15 -14
  201. package/dist/types/wallets/MinimalBitcoinWalletInterface.d.ts +23 -23
  202. package/dist/types/wallets/MinimalBitcoinWalletInterface.js +2 -2
  203. package/dist/types/wallets/MinimalLightningNetworkWalletInterface.d.ts +9 -9
  204. package/dist/types/wallets/MinimalLightningNetworkWalletInterface.js +2 -2
  205. package/dist/utils/AutomaticClockDriftCorrection.d.ts +1 -1
  206. package/dist/utils/AutomaticClockDriftCorrection.js +70 -69
  207. package/dist/utils/BitcoinUtils.d.ts +14 -12
  208. package/dist/utils/BitcoinUtils.js +102 -101
  209. package/dist/utils/BitcoinWalletUtils.d.ts +7 -7
  210. package/dist/utils/BitcoinWalletUtils.js +14 -13
  211. package/dist/utils/Logger.d.ts +7 -7
  212. package/dist/utils/Logger.js +12 -11
  213. package/dist/utils/RetryUtils.d.ts +22 -22
  214. package/dist/utils/RetryUtils.js +67 -66
  215. package/dist/utils/SwapUtils.d.ts +88 -88
  216. package/dist/utils/SwapUtils.js +72 -72
  217. package/dist/utils/TimeoutUtils.d.ts +17 -17
  218. package/dist/utils/TimeoutUtils.js +55 -54
  219. package/dist/utils/TokenUtils.d.ts +19 -19
  220. package/dist/utils/TokenUtils.js +37 -36
  221. package/dist/utils/TypeUtils.d.ts +7 -7
  222. package/dist/utils/TypeUtils.js +2 -2
  223. package/dist/utils/Utils.d.ts +58 -56
  224. package/dist/utils/Utils.js +194 -193
  225. package/package.json +1 -1
@@ -1,1371 +1,1371 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FromBTCLNAutoSwap = exports.FromBTCLNAutoSwapState = void 0;
4
- exports.isFromBTCLNAutoSwapInit = isFromBTCLNAutoSwapInit;
5
- const bolt11_1 = require("@atomiqlabs/bolt11");
6
- const SwapType_1 = require("../../../../enums/SwapType");
7
- const base_1 = require("@atomiqlabs/base");
8
- const buffer_1 = require("buffer");
9
- const LNURL_1 = require("../../../../lnurl/LNURL");
10
- const UserError_1 = require("../../../../errors/UserError");
11
- const IntermediaryAPI_1 = require("../../../../intermediaries/apis/IntermediaryAPI");
12
- const IntermediaryError_1 = require("../../../../errors/IntermediaryError");
13
- const Utils_1 = require("../../../../utils/Utils");
14
- const IEscrowSwap_1 = require("../../IEscrowSwap");
15
- const FeeType_1 = require("../../../../enums/FeeType");
16
- const PercentagePPM_1 = require("../../../../types/fees/PercentagePPM");
17
- const TokenAmount_1 = require("../../../../types/TokenAmount");
18
- const Token_1 = require("../../../../types/Token");
19
- const Logger_1 = require("../../../../utils/Logger");
20
- const TimeoutUtils_1 = require("../../../../utils/TimeoutUtils");
21
- const LNURLWithdraw_1 = require("../../../../types/lnurl/LNURLWithdraw");
22
- const PriceInfoType_1 = require("../../../../types/PriceInfoType");
23
- const sha2_1 = require("@noble/hashes/sha2");
24
- /**
25
- * State enum for FromBTCLNAuto swaps
26
- * @category Swaps/Lightning → Smart chain
27
- */
28
- var FromBTCLNAutoSwapState;
29
- (function (FromBTCLNAutoSwapState) {
30
- /**
31
- * Swap has failed as the user didn't settle the HTLC on the destination before expiration
32
- */
33
- FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["FAILED"] = -4] = "FAILED";
34
- /**
35
- * Swap has expired for good and there is no way how it can be executed anymore
36
- */
37
- FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["QUOTE_EXPIRED"] = -3] = "QUOTE_EXPIRED";
38
- /**
39
- * A swap is almost expired, and it should be presented to the user as expired, though
40
- * there is still a chance that it will be processed
41
- */
42
- FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["QUOTE_SOFT_EXPIRED"] = -2] = "QUOTE_SOFT_EXPIRED";
43
- /**
44
- * Swap HTLC on the destination chain has expired, it is not safe anymore to settle (claim) the
45
- * swap on the destination smart chain.
46
- */
47
- FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["EXPIRED"] = -1] = "EXPIRED";
48
- /**
49
- * Swap quote was created, use {@link FromBTCLNAutoSwap.getAddress} or {@link FromBTCLNAutoSwap.getHyperlink}
50
- * to get the bolt11 lightning network invoice to pay to initiate the swap, then use the
51
- * {@link FromBTCLNAutoSwap.waitForPayment} to wait till the lightning network payment is received
52
- * by the intermediary (LP) and the destination HTLC escrow is created
53
- */
54
- FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["PR_CREATED"] = 0] = "PR_CREATED";
55
- /**
56
- * Lightning network payment has been received by the intermediary (LP), but the destination chain
57
- * HTLC escrow hasn't been created yet. Use {@link FromBTCLNAutoSwap.waitForPayment} to continue waiting
58
- * till the destination HTLC escrow is created.
59
- */
60
- FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["PR_PAID"] = 1] = "PR_PAID";
61
- /**
62
- * Swap escrow HTLC has been created on the destination chain, wait for automatic settlement by the watchtowers
63
- * using the {@link FromBTCLNAutoSwap.waitTillClaimed} function or settle manually using the
64
- * {@link FromBTCLNAutoSwap.claim} or {@link FromBTCLNAutoSwap.txsClaim} function.
65
- */
66
- FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["CLAIM_COMMITED"] = 2] = "CLAIM_COMMITED";
67
- /**
68
- * Swap successfully settled and funds received on the destination chain
69
- */
70
- FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["CLAIM_CLAIMED"] = 3] = "CLAIM_CLAIMED";
71
- })(FromBTCLNAutoSwapState || (exports.FromBTCLNAutoSwapState = FromBTCLNAutoSwapState = {}));
72
- const FromBTCLNAutoSwapStateDescription = {
73
- [FromBTCLNAutoSwapState.FAILED]: "Swap has failed as the user didn't settle the HTLC on the destination before expiration",
74
- [FromBTCLNAutoSwapState.QUOTE_EXPIRED]: "Swap has expired for good and there is no way how it can be executed anymore",
75
- [FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED]: "A swap is expired, though there is still a chance that it will be processed",
76
- [FromBTCLNAutoSwapState.EXPIRED]: "Swap HTLC on the destination chain has expired, it is not safe anymore to settle (claim) the swap on the destination smart chain.",
77
- [FromBTCLNAutoSwapState.PR_CREATED]: "Swap quote was created, pay the bolt11 lightning network invoice to initiate the swap, then wait till the lightning network payment is received by the intermediary (LP) and the destination HTLC escrow is created",
78
- [FromBTCLNAutoSwapState.PR_PAID]: "Lightning network payment has been received by the intermediary (LP), but the destination chain HTLC escrow hasn't been created yet. Continue waiting till the destination HTLC escrow is created.",
79
- [FromBTCLNAutoSwapState.CLAIM_COMMITED]: "Swap escrow HTLC has been created on the destination chain, wait for automatic settlement by the watchtowers or settle manually.",
80
- [FromBTCLNAutoSwapState.CLAIM_CLAIMED]: "Swap successfully settled and funds received on the destination chain"
81
- };
82
- function isFromBTCLNAutoSwapInit(obj) {
83
- return (obj.pr == null || typeof obj.pr === "string") &&
84
- (obj.secret == null || typeof obj.secret === "string") &&
85
- (obj.btcAmountSwap == null || typeof obj.btcAmountSwap === "bigint") &&
86
- (obj.btcAmountGas == null || typeof obj.btcAmountGas === "bigint") &&
87
- typeof obj.gasSwapFeeBtc === "bigint" &&
88
- typeof obj.gasSwapFee === "bigint" &&
89
- (obj.gasPricingInfo == null || (0, PriceInfoType_1.isPriceInfoType)(obj.gasPricingInfo)) &&
90
- (obj.lnurl == null || typeof (obj.lnurl) === "string") &&
91
- (obj.lnurlK1 == null || typeof (obj.lnurlK1) === "string") &&
92
- (obj.lnurlCallback == null || typeof (obj.lnurlCallback) === "string") &&
93
- (0, IEscrowSwap_1.isIEscrowSwapInit)(obj);
94
- }
95
- /**
96
- * New escrow based (HTLC) swaps for Bitcoin Lightning -> Smart chain swaps not requiring manual settlement on
97
- * the destination by the user, and instead letting the LP initiate the escrow. Permissionless watchtower network
98
- * handles the claiming of HTLC, with the swap secret broadcasted over Nostr. Also adds a possibility for the user
99
- * to receive a native token on the destination chain as part of the swap (a "gas drop" feature).
100
- *
101
- * @category Swaps/Lightning → Smart chain
102
- */
103
- class FromBTCLNAutoSwap extends IEscrowSwap_1.IEscrowSwap {
104
- /**
105
- * Sets the LNURL data for the swap
106
- *
107
- * @internal
108
- */
109
- _setLNURLData(lnurl, lnurlK1, lnurlCallback) {
110
- this.lnurl = lnurl;
111
- this.lnurlK1 = lnurlK1;
112
- this.lnurlCallback = lnurlCallback;
113
- }
114
- constructor(wrapper, initOrObject) {
115
- if (isFromBTCLNAutoSwapInit(initOrObject) && initOrObject.url != null)
116
- initOrObject.url += "/frombtcln_auto";
117
- super(wrapper, initOrObject);
118
- this.TYPE = SwapType_1.SwapType.FROM_BTCLN_AUTO;
119
- /**
120
- * @internal
121
- */
122
- this.swapStateName = (state) => FromBTCLNAutoSwapState[state];
123
- /**
124
- * @internal
125
- */
126
- this.swapStateDescription = FromBTCLNAutoSwapStateDescription;
127
- /**
128
- * @internal
129
- */
130
- this.inputToken = Token_1.BitcoinTokens.BTCLN;
131
- this.lnurlFailSignal = new AbortController();
132
- this.prPosted = false;
133
- this.broadcastTickCounter = 0;
134
- if (isFromBTCLNAutoSwapInit(initOrObject)) {
135
- this._state = FromBTCLNAutoSwapState.PR_CREATED;
136
- this.pr = initOrObject.pr;
137
- this.secret = initOrObject.secret;
138
- this.initialSwapData = initOrObject.initialSwapData;
139
- this.btcAmountSwap = initOrObject.btcAmountSwap;
140
- this.btcAmountGas = initOrObject.btcAmountGas;
141
- this.gasSwapFeeBtc = initOrObject.gasSwapFeeBtc;
142
- this.gasSwapFee = initOrObject.gasSwapFee;
143
- this.gasPricingInfo = initOrObject.gasPricingInfo;
144
- this.lnurl = initOrObject.lnurl;
145
- this.lnurlK1 = initOrObject.lnurlK1;
146
- this.lnurlCallback = initOrObject.lnurlCallback;
147
- this.usesClaimHashAsId = true;
148
- }
149
- else {
150
- this.pr = initOrObject.pr;
151
- this.secret = initOrObject.secret;
152
- if (initOrObject.initialSwapData == null) {
153
- this.initialSwapData = this._data;
154
- }
155
- else {
156
- this.initialSwapData = base_1.SwapData.deserialize(initOrObject.initialSwapData);
157
- }
158
- this.btcAmountSwap = (0, Utils_1.toBigInt)(initOrObject.btcAmountSwap);
159
- this.btcAmountGas = (0, Utils_1.toBigInt)(initOrObject.btcAmountGas);
160
- this.gasSwapFeeBtc = (0, Utils_1.toBigInt)(initOrObject.gasSwapFeeBtc);
161
- this.gasSwapFee = (0, Utils_1.toBigInt)(initOrObject.gasSwapFee);
162
- this.gasPricingInfo = (0, PriceInfoType_1.deserializePriceInfoType)(initOrObject.gasPricingInfo);
163
- this._commitTxId = initOrObject.commitTxId;
164
- this._claimTxId = initOrObject.claimTxId;
165
- this._commitedAt = initOrObject.commitedAt;
166
- this.lnurl = initOrObject.lnurl;
167
- this.lnurlK1 = initOrObject.lnurlK1;
168
- this.lnurlCallback = initOrObject.lnurlCallback;
169
- this.prPosted = initOrObject.prPosted;
170
- this.usesClaimHashAsId = initOrObject.usesClaimHashAsId ?? false;
171
- }
172
- this.tryRecomputeSwapPrice();
173
- this.logger = (0, Logger_1.getLogger)("FromBTCLNAuto(" + this.getIdentifierHashString() + "): ");
174
- }
175
- /**
176
- * @inheritDoc
177
- * @internal
178
- */
179
- getSwapData() {
180
- return this._data ?? this.initialSwapData;
181
- }
182
- /**
183
- * @inheritDoc
184
- * @internal
185
- */
186
- upgradeVersion() { }
187
- /**
188
- * @inheritDoc
189
- * @internal
190
- */
191
- tryRecomputeSwapPrice() {
192
- if (this.pricingInfo == null || this.btcAmountSwap == null)
193
- return;
194
- if (this.pricingInfo.swapPriceUSatPerToken == null) {
195
- const priceUsdPerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
196
- this.pricingInfo = this.wrapper._prices.recomputePriceInfoReceive(this.chainIdentifier, this.btcAmountSwap, this.pricingInfo.satsBaseFee, this.pricingInfo.feePPM, this.getOutputAmountWithoutFee(), this.getSwapData().getToken());
197
- this.pricingInfo.realPriceUsdPerBitcoin = priceUsdPerBtc;
198
- }
199
- }
200
- //////////////////////////////
201
- //// Pricing
202
- /**
203
- * @inheritDoc
204
- */
205
- async refreshPriceData() {
206
- if (this.pricingInfo == null || this.btcAmountSwap == null)
207
- return;
208
- const usdPricePerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
209
- this.pricingInfo = await this.wrapper._prices.isValidAmountReceive(this.chainIdentifier, this.btcAmountSwap, this.pricingInfo.satsBaseFee, this.pricingInfo.feePPM, this.getOutputAmountWithoutFee(), this.getSwapData().getToken(), undefined, undefined, this.swapFeeBtc);
210
- this.pricingInfo.realPriceUsdPerBitcoin = usdPricePerBtc;
211
- }
212
- //////////////////////////////
213
- //// Getters & utils
214
- /**
215
- * @inheritDoc
216
- * @internal
217
- */
218
- _getEscrowHash() {
219
- //Use claim hash in case the data is not yet known
220
- return this._data == null ? this.initialSwapData?.getClaimHash() : this._data?.getEscrowHash();
221
- }
222
- /**
223
- * @inheritDoc
224
- * @internal
225
- */
226
- _getInitiator() {
227
- return this.getSwapData().getClaimer();
228
- }
229
- /**
230
- * @inheritDoc
231
- */
232
- getId() {
233
- return this.getIdentifierHashString();
234
- }
235
- /**
236
- * @inheritDoc
237
- */
238
- getOutputAddress() {
239
- return this._getInitiator();
240
- }
241
- /**
242
- * @inheritDoc
243
- */
244
- getOutputTxId() {
245
- return this._claimTxId ?? null;
246
- }
247
- /**
248
- * @inheritDoc
249
- */
250
- requiresAction() {
251
- return this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED;
252
- }
253
- /**
254
- * @inheritDoc
255
- * @internal
256
- */
257
- getIdentifierHashString() {
258
- const id = this.usesClaimHashAsId
259
- ? this.getClaimHash()
260
- : this.getPaymentHash().toString("hex");
261
- if (this._randomNonce == null)
262
- return id;
263
- return id + this._randomNonce;
264
- }
265
- /**
266
- * Returns the payment hash of the swap and lightning network invoice, or `null` if not known (i.e. if
267
- * the swap was recovered from on-chain data, the payment hash might not be known)
268
- *
269
- * @internal
270
- */
271
- getPaymentHash() {
272
- if (this.pr == null)
273
- return null;
274
- if (this.pr.toLowerCase().startsWith("ln")) {
275
- const parsed = (0, bolt11_1.decode)(this.pr);
276
- if (parsed.tagsObject.payment_hash == null)
277
- throw new Error("Swap invoice has no payment hash field!");
278
- return buffer_1.Buffer.from(parsed.tagsObject.payment_hash, "hex");
279
- }
280
- return buffer_1.Buffer.from(this.pr, "hex");
281
- }
282
- /**
283
- * @inheritDoc
284
- */
285
- getInputAddress() {
286
- return this.lnurl ?? this.pr ?? null;
287
- }
288
- /**
289
- * @inheritDoc
290
- */
291
- getInputTxId() {
292
- const paymentHash = this.getPaymentHash();
293
- if (paymentHash == null)
294
- return null;
295
- return paymentHash.toString("hex");
296
- }
297
- /**
298
- * Returns the lightning network BOLT11 invoice that needs to be paid as an input to the swap
299
- */
300
- getAddress() {
301
- return this.pr ?? "";
302
- }
303
- /**
304
- * @inheritDoc
305
- */
306
- getHyperlink() {
307
- return this.pr == null ? "" : "lightning:" + this.pr.toUpperCase();
308
- }
309
- /**
310
- * Returns the timeout time (in UNIX milliseconds) when the swap will definitelly be considered as expired
311
- * if the LP doesn't make it expired sooner
312
- */
313
- getDefinitiveExpiryTime() {
314
- if (this.pr == null || !this.pr.toLowerCase().startsWith("ln"))
315
- return 0;
316
- const decoded = (0, bolt11_1.decode)(this.pr);
317
- if (decoded.tagsObject.min_final_cltv_expiry == null)
318
- throw new Error("Swap invoice doesn't contain final ctlv delta field!");
319
- if (decoded.timeExpireDate == null)
320
- throw new Error("Swap invoice doesn't contain expiry date field!");
321
- const finalCltvExpiryDelta = decoded.tagsObject.min_final_cltv_expiry ?? 144;
322
- const finalCltvExpiryDelay = finalCltvExpiryDelta * this.wrapper._options.bitcoinBlocktime * this.wrapper._options.safetyFactor;
323
- return (decoded.timeExpireDate + finalCltvExpiryDelay) * 1000;
324
- }
325
- /**
326
- * Returns timeout time (in UNIX milliseconds) when the swap htlc will expire
327
- */
328
- getHtlcTimeoutTime() {
329
- return this._data == null ? null : Number(this.wrapper._getHtlcTimeout(this._data)) * 1000;
330
- }
331
- /**
332
- * @inheritDoc
333
- */
334
- isFinished() {
335
- return this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED || this._state === FromBTCLNAutoSwapState.QUOTE_EXPIRED || this._state === FromBTCLNAutoSwapState.FAILED;
336
- }
337
- /**
338
- * @inheritDoc
339
- */
340
- isClaimable() {
341
- return this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED;
342
- }
343
- /**
344
- * @inheritDoc
345
- */
346
- isSuccessful() {
347
- return this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED;
348
- }
349
- /**
350
- * @inheritDoc
351
- */
352
- isFailed() {
353
- return this._state === FromBTCLNAutoSwapState.FAILED || this._state === FromBTCLNAutoSwapState.EXPIRED;
354
- }
355
- /**
356
- * @inheritDoc
357
- */
358
- isInProgress() {
359
- return (this._state === FromBTCLNAutoSwapState.PR_CREATED && this.initiated) ||
360
- (this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED && this.initiated) ||
361
- this._state === FromBTCLNAutoSwapState.PR_PAID ||
362
- this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED;
363
- }
364
- /**
365
- * @inheritDoc
366
- */
367
- isQuoteExpired() {
368
- return this._state === FromBTCLNAutoSwapState.QUOTE_EXPIRED;
369
- }
370
- /**
371
- * @inheritDoc
372
- */
373
- isQuoteSoftExpired() {
374
- return this._state === FromBTCLNAutoSwapState.QUOTE_EXPIRED;
375
- }
376
- /**
377
- * @inheritDoc
378
- */
379
- _verifyQuoteDefinitelyExpired() {
380
- return Promise.resolve(this.getDefinitiveExpiryTime() < Date.now());
381
- }
382
- /**
383
- * @inheritDoc
384
- */
385
- _verifyQuoteValid() {
386
- return Promise.resolve(this.getQuoteExpiry() > Date.now());
387
- }
388
- //////////////////////////////
389
- //// Amounts & fees
390
- /**
391
- * Returns the satoshi amount of the lightning network invoice, or `null` if the lightning network
392
- * invoice is not known (i.e. when the swap was recovered from on-chain data, the paid invoice
393
- * cannot be recovered because it is purely off-chain)
394
- *
395
- * @internal
396
- */
397
- getLightningInvoiceSats() {
398
- if (this.pr == null || !this.pr.toLowerCase().startsWith("ln"))
399
- return null;
400
- const parsed = (0, bolt11_1.decode)(this.pr);
401
- if (parsed.millisatoshis == null)
402
- throw new Error("Swap invoice doesn't contain msat amount field!");
403
- return (BigInt(parsed.millisatoshis) + 999n) / 1000n;
404
- }
405
- /**
406
- * Returns the watchtower fee paid in BTC satoshis, or null if known (i.e. if the swap was recovered from
407
- * on-chain data)
408
- *
409
- * @protected
410
- */
411
- getWatchtowerFeeAmountBtc() {
412
- if (this.btcAmountGas == null)
413
- return null;
414
- return (this.btcAmountGas - this.gasSwapFeeBtc) * this.getSwapData().getClaimerBounty() / this.getSwapData().getTotalDeposit();
415
- }
416
- /**
417
- * Returns the input amount for the actual swap (excluding the input amount used to cover the "gas drop"
418
- * part of the swap), excluding fees
419
- *
420
- * @internal
421
- */
422
- getInputSwapAmountWithoutFee() {
423
- if (this.btcAmountSwap == null)
424
- return null;
425
- return this.btcAmountSwap - this.swapFeeBtc;
426
- }
427
- /**
428
- * Returns the input amount purely for the "gas drop" part of the swap (this much BTC in sats will be
429
- * swapped into the native gas token on the destination chain), excluding fees
430
- *
431
- * @internal
432
- */
433
- getInputGasAmountWithoutFee() {
434
- if (this.btcAmountGas == null)
435
- return null;
436
- return this.btcAmountGas - this.gasSwapFeeBtc;
437
- }
438
- /**
439
- * Get total btc amount in sats on the input, excluding the swap fee and watchtower fee
440
- *
441
- * @internal
442
- */
443
- getInputAmountWithoutFee() {
444
- if (this.btcAmountGas == null || this.btcAmountSwap == null)
445
- return null;
446
- return this.getInputSwapAmountWithoutFee() + this.getInputGasAmountWithoutFee() - this.getWatchtowerFeeAmountBtc();
447
- }
448
- /**
449
- * Returns the "would be" output amount if the swap charged no swap fee
450
- *
451
- * @internal
452
- */
453
- getOutputAmountWithoutFee() {
454
- return this.getSwapData().getAmount() + this.swapFee;
455
- }
456
- /**
457
- * @inheritDoc
458
- */
459
- getInputToken() {
460
- return Token_1.BitcoinTokens.BTCLN;
461
- }
462
- /**
463
- * @inheritDoc
464
- */
465
- getInput() {
466
- return (0, TokenAmount_1.toTokenAmount)(this.getLightningInvoiceSats(), this.inputToken, this.wrapper._prices, this.pricingInfo);
467
- }
468
- /**
469
- * @inheritDoc
470
- */
471
- getInputWithoutFee() {
472
- return (0, TokenAmount_1.toTokenAmount)(this.getInputAmountWithoutFee(), this.inputToken, this.wrapper._prices, this.pricingInfo);
473
- }
474
- /**
475
- * @inheritDoc
476
- */
477
- getOutputToken() {
478
- return this.wrapper._tokens[this.getSwapData().getToken()];
479
- }
480
- /**
481
- * @inheritDoc
482
- */
483
- getOutput() {
484
- return (0, TokenAmount_1.toTokenAmount)(this.getSwapData().getAmount(), this.wrapper._tokens[this.getSwapData().getToken()], this.wrapper._prices, this.pricingInfo);
485
- }
486
- /**
487
- * @inheritDoc
488
- */
489
- getGasDropOutput() {
490
- return (0, TokenAmount_1.toTokenAmount)(this.getSwapData().getSecurityDeposit() - this.getSwapData().getClaimerBounty(), this.wrapper._tokens[this.getSwapData().getDepositToken()], this.wrapper._prices, this.gasPricingInfo);
491
- }
492
- /**
493
- * Returns the swap fee charged by the intermediary (LP) on this swap
494
- *
495
- * @internal
496
- */
497
- getSwapFee() {
498
- if (this.pricingInfo == null)
499
- throw new Error("No pricing info known, cannot estimate fee!");
500
- const outputToken = this.wrapper._tokens[this.getSwapData().getToken()];
501
- const gasSwapFeeInOutputToken = this.gasSwapFeeBtc
502
- * (10n ** BigInt(outputToken.decimals))
503
- * 1000000n
504
- / this.pricingInfo.swapPriceUSatPerToken;
505
- const feeWithoutBaseFee = this.gasSwapFeeBtc + this.swapFeeBtc - this.pricingInfo.satsBaseFee;
506
- const inputSats = this.getLightningInvoiceSats();
507
- const swapFeePPM = inputSats != null
508
- ? feeWithoutBaseFee * 1000000n / (inputSats - this.swapFeeBtc - this.gasSwapFeeBtc)
509
- : 0n;
510
- const amountInSrcToken = (0, TokenAmount_1.toTokenAmount)(this.swapFeeBtc + this.gasSwapFeeBtc, Token_1.BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo);
511
- return {
512
- amountInSrcToken,
513
- amountInDstToken: (0, TokenAmount_1.toTokenAmount)(this.swapFee + gasSwapFeeInOutputToken, outputToken, this.wrapper._prices, this.pricingInfo),
514
- currentUsdValue: amountInSrcToken.currentUsdValue,
515
- pastUsdValue: amountInSrcToken.pastUsdValue,
516
- usdValue: amountInSrcToken.usdValue,
517
- composition: {
518
- base: (0, TokenAmount_1.toTokenAmount)(this.pricingInfo.satsBaseFee, Token_1.BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo),
519
- percentage: (0, PercentagePPM_1.ppmToPercentage)(swapFeePPM)
520
- }
521
- };
522
- }
523
- /**
524
- * Returns the fee to be paid to watchtowers on the destination chain to automatically
525
- * process and settle this swap without requiring any user interaction
526
- *
527
- * @internal
528
- */
529
- getWatchtowerFee() {
530
- if (this.pricingInfo == null)
531
- throw new Error("No pricing info known, cannot estimate fee!");
532
- const btcWatchtowerFee = this.getWatchtowerFeeAmountBtc();
533
- const outputToken = this.wrapper._tokens[this.getSwapData().getToken()];
534
- const watchtowerFeeInOutputToken = btcWatchtowerFee == null ? 0n : btcWatchtowerFee
535
- * (10n ** BigInt(outputToken.decimals))
536
- * 1000000n
537
- / this.pricingInfo.swapPriceUSatPerToken;
538
- const amountInSrcToken = (0, TokenAmount_1.toTokenAmount)(btcWatchtowerFee, Token_1.BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo);
539
- return {
540
- amountInSrcToken,
541
- amountInDstToken: (0, TokenAmount_1.toTokenAmount)(watchtowerFeeInOutputToken, outputToken, this.wrapper._prices, this.pricingInfo),
542
- currentUsdValue: amountInSrcToken.currentUsdValue,
543
- usdValue: amountInSrcToken.usdValue,
544
- pastUsdValue: amountInSrcToken.pastUsdValue
545
- };
546
- }
547
- /**
548
- * @inheritDoc
549
- */
550
- getFee() {
551
- const swapFee = this.getSwapFee();
552
- const watchtowerFee = this.getWatchtowerFee();
553
- const amountInSrcToken = (0, TokenAmount_1.toTokenAmount)(swapFee.amountInSrcToken.rawAmount + watchtowerFee.amountInSrcToken.rawAmount, Token_1.BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo);
554
- return {
555
- amountInSrcToken,
556
- amountInDstToken: (0, TokenAmount_1.toTokenAmount)(swapFee.amountInDstToken.rawAmount + watchtowerFee.amountInDstToken.rawAmount, this.wrapper._tokens[this.getSwapData().getToken()], this.wrapper._prices, this.pricingInfo),
557
- currentUsdValue: amountInSrcToken.currentUsdValue,
558
- usdValue: amountInSrcToken.usdValue,
559
- pastUsdValue: amountInSrcToken.pastUsdValue
560
- };
561
- }
562
- /**
563
- * @inheritDoc
564
- */
565
- getFeeBreakdown() {
566
- return [
567
- {
568
- type: FeeType_1.FeeType.SWAP,
569
- fee: this.getSwapFee()
570
- },
571
- {
572
- type: FeeType_1.FeeType.NETWORK_OUTPUT,
573
- fee: this.getWatchtowerFee()
574
- }
575
- ];
576
- }
577
- isValidSecretPreimage(secret) {
578
- const paymentHash = buffer_1.Buffer.from((0, sha2_1.sha256)(buffer_1.Buffer.from(secret, "hex")));
579
- const claimHash = this.wrapper._contract.getHashForHtlc(paymentHash).toString("hex");
580
- return this.getSwapData().getClaimHash() === claimHash;
581
- }
582
- /**
583
- * Sets the secret preimage for the swap, in case it is not known already
584
- *
585
- * @param secret Secret preimage that matches the expected payment hash
586
- *
587
- * @throws {Error} If an invalid secret preimage is provided
588
- */
589
- setSecretPreimage(secret) {
590
- if (!this.isValidSecretPreimage(secret))
591
- throw new Error("Invalid secret preimage provided, hash doesn't match!");
592
- this.secret = secret;
593
- }
594
- /**
595
- * Returns whether the secret preimage for this swap is known
596
- */
597
- hasSecretPreimage() {
598
- return this.secret != null;
599
- }
600
- //////////////////////////////
601
- //// Execution
602
- /**
603
- * Executes the swap with the provided bitcoin lightning network wallet or LNURL
604
- *
605
- * @param walletOrLnurlWithdraw Bitcoin lightning wallet to use to pay the lightning network invoice, or an LNURL-withdraw
606
- * link, wallet is not required and the LN invoice can be paid externally as well (just pass null or undefined here)
607
- * @param callbacks Callbacks to track the progress of the swap
608
- * @param options Optional options for the swap like AbortSignal, and timeouts/intervals
609
- * @param options.secret A swap secret to broadcast to watchtowers, generally only needed if the swap
610
- * was recovered from on-chain data, or the pre-image was generated outside the SDK
611
- *
612
- * @returns {boolean} Whether a swap was settled automatically by swap watchtowers or requires manual claim by the
613
- * user, in case `false` is returned the user should call `swap.claim()` to settle the swap on the destination manually
614
- */
615
- async execute(walletOrLnurlWithdraw, callbacks, options) {
616
- if (this._state === FromBTCLNAutoSwapState.FAILED)
617
- throw new Error("Swap failed!");
618
- if (this._state === FromBTCLNAutoSwapState.EXPIRED)
619
- throw new Error("Swap HTLC expired!");
620
- if (this._state === FromBTCLNAutoSwapState.QUOTE_EXPIRED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED)
621
- throw new Error("Swap quote expired!");
622
- if (this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED)
623
- throw new Error("Swap already settled!");
624
- let abortSignal = options?.abortSignal;
625
- if (this._state === FromBTCLNAutoSwapState.PR_CREATED) {
626
- if (walletOrLnurlWithdraw != null && this.lnurl == null) {
627
- if (this.pr == null || !this.pr.toLowerCase().startsWith("ln"))
628
- throw new Error("Input lightning network invoice not available, the swap was probably recovered!");
629
- if (typeof (walletOrLnurlWithdraw) === "string" || (0, LNURLWithdraw_1.isLNURLWithdraw)(walletOrLnurlWithdraw)) {
630
- await this.settleWithLNURLWithdraw(walletOrLnurlWithdraw);
631
- }
632
- else {
633
- const paymentPromise = walletOrLnurlWithdraw.payInvoice(this.pr);
634
- const abortController = new AbortController();
635
- paymentPromise.catch(e => abortController.abort(e));
636
- if (options?.abortSignal != null)
637
- options.abortSignal.addEventListener("abort", () => abortController.abort(options?.abortSignal?.reason));
638
- abortSignal = abortController.signal;
639
- }
640
- }
641
- }
642
- if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.PR_PAID) {
643
- const paymentSuccess = await this.waitForPayment(callbacks?.onSourceTransactionReceived, options?.lightningTxCheckIntervalSeconds, abortSignal);
644
- if (!paymentSuccess)
645
- throw new Error("Failed to receive lightning network payment");
646
- }
647
- if (this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED)
648
- return true;
649
- if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED) {
650
- if (this.secret == null && options?.secret == null)
651
- throw new Error("Tried to wait till settlement, but no secret pre-image is known, please pass the secret pre-image as an argument!");
652
- const success = await this.waitTillClaimed(options?.maxWaitTillAutomaticSettlementSeconds ?? 60, options?.abortSignal, options?.secret);
653
- if (success && callbacks?.onSwapSettled != null)
654
- callbacks.onSwapSettled(this.getOutputTxId());
655
- return success;
656
- }
657
- throw new Error("Invalid state reached!");
658
- }
659
- /**
660
- * @inheritDoc
661
- */
662
- async txsExecute() {
663
- if (this._state === FromBTCLNAutoSwapState.PR_CREATED) {
664
- if (!await this._verifyQuoteValid())
665
- throw new Error("Quote already expired or close to expiry!");
666
- return [
667
- {
668
- name: "Payment",
669
- description: "Initiates the swap by paying up the lightning network invoice",
670
- chain: "LIGHTNING",
671
- txs: [
672
- {
673
- type: "BOLT11_PAYMENT_REQUEST",
674
- address: this.getAddress(),
675
- hyperlink: this.getHyperlink()
676
- }
677
- ]
678
- }
679
- ];
680
- }
681
- throw new Error("Invalid swap state to obtain execution txns, required PR_CREATED");
682
- }
683
- /**
684
- *
685
- * @param options.manualSettlementSmartChainSigner Optional smart chain signer to create a manual claim (settlement) transaction
686
- * @param options.maxWaitTillAutomaticSettlementSeconds Maximum time to wait for an automatic settlement after
687
- * the bitcoin transaction is confirmed (defaults to 60 seconds)
688
- * @param options.secret A swap secret to broadcast to watchtowers, generally only needed if the swap
689
- * was recovered from on-chain data, or the pre-image was generated outside the SDK
690
- */
691
- async getCurrentActions(options) {
692
- if (options?.secret != null)
693
- this.setSecretPreimage(options.secret);
694
- if (this._state === FromBTCLNAutoSwapState.PR_CREATED) {
695
- try {
696
- return await this.txsExecute();
697
- }
698
- catch (e) { }
699
- }
700
- if (this.isClaimable()) {
701
- if (this._commitedAt == null ||
702
- options?.maxWaitTillAutomaticSettlementSeconds === 0 ||
703
- (Date.now() - this._commitedAt) > (options?.maxWaitTillAutomaticSettlementSeconds ?? 60) * 1000) {
704
- return [{
705
- name: "Claim",
706
- description: "Manually settle (claim) the swap on the destination smart chain",
707
- chain: this.chainIdentifier,
708
- txs: await this.txsClaim(options?.manualSettlementSmartChainSigner)
709
- }];
710
- }
711
- }
712
- return [];
713
- }
714
- //////////////////////////////
715
- //// Payment
716
- /**
717
- * Checks whether the LP received the LN payment
718
- *
719
- * @param save If the new swap state should be saved
720
- *
721
- * @internal
722
- */
723
- async _checkIntermediaryPaymentReceived(save = true) {
724
- if (this._state === FromBTCLNAutoSwapState.PR_PAID ||
725
- this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED ||
726
- this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED ||
727
- this._state === FromBTCLNAutoSwapState.FAILED ||
728
- this._state === FromBTCLNAutoSwapState.EXPIRED)
729
- return true;
730
- if (this._state === FromBTCLNAutoSwapState.QUOTE_EXPIRED)
731
- return false;
732
- if (this.url == null)
733
- return false;
734
- const paymentHash = this.getPaymentHash();
735
- if (paymentHash == null)
736
- throw new Error("Failed to check LP payment received, payment hash not known (probably recovered swap?)");
737
- const resp = await IntermediaryAPI_1.IntermediaryAPI.getInvoiceStatus(this.url, paymentHash.toString("hex"));
738
- switch (resp.code) {
739
- case IntermediaryAPI_1.InvoiceStatusResponseCodes.PAID:
740
- const data = new this.wrapper._swapDataDeserializer(resp.data.data);
741
- if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED)
742
- try {
743
- await this._saveRealSwapData(data, save);
744
- return true;
745
- }
746
- catch (e) { }
747
- return null;
748
- case IntermediaryAPI_1.InvoiceStatusResponseCodes.EXPIRED:
749
- this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
750
- this.initiated = true;
751
- if (save)
752
- await this._saveAndEmit();
753
- return false;
754
- default:
755
- return null;
756
- }
757
- }
758
- /**
759
- * Checks and overrides the swap data for this swap. This is used to set the swap data from
760
- * on-chain events.
761
- *
762
- * @param data Swap data of the escrow swap
763
- * @param save If the new data should be saved
764
- *
765
- * @internal
766
- */
767
- async _saveRealSwapData(data, save) {
768
- await this.checkIntermediaryReturnedData(data);
769
- if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
770
- this._state = FromBTCLNAutoSwapState.PR_PAID;
771
- this._data = data;
772
- this.initiated = true;
773
- if (save)
774
- await this._saveAndEmit();
775
- return true;
776
- }
777
- return false;
778
- }
779
- /**
780
- * Checks the data returned by the intermediary in the payment auth request
781
- *
782
- * @param data Parsed swap data as returned by the intermediary
783
- *
784
- * @throws {IntermediaryError} If the returned are not valid
785
- * @throws {Error} If the swap is already committed on-chain
786
- *
787
- * @private
788
- */
789
- async checkIntermediaryReturnedData(data) {
790
- if (!data.isPayOut())
791
- throw new IntermediaryError_1.IntermediaryError("Invalid not pay out");
792
- if (data.getType() !== base_1.ChainSwapType.HTLC)
793
- throw new IntermediaryError_1.IntermediaryError("Invalid swap type");
794
- if (!data.isOfferer(this.getSwapData().getOfferer()))
795
- throw new IntermediaryError_1.IntermediaryError("Invalid offerer used");
796
- if (!data.isClaimer(this._getInitiator()))
797
- throw new IntermediaryError_1.IntermediaryError("Invalid claimer used");
798
- if (!data.isToken(this.getSwapData().getToken()))
799
- throw new IntermediaryError_1.IntermediaryError("Invalid token used");
800
- if (data.getSecurityDeposit() !== this.getSwapData().getSecurityDeposit())
801
- throw new IntermediaryError_1.IntermediaryError("Invalid security deposit!");
802
- if (data.getClaimerBounty() !== this.getSwapData().getClaimerBounty())
803
- throw new IntermediaryError_1.IntermediaryError("Invalid security deposit!");
804
- if (data.getAmount() < this.getSwapData().getAmount())
805
- throw new IntermediaryError_1.IntermediaryError("Invalid amount received!");
806
- if (data.getClaimHash() !== this.getSwapData().getClaimHash())
807
- throw new IntermediaryError_1.IntermediaryError("Invalid payment hash used!");
808
- if (!data.isDepositToken(this.getSwapData().getDepositToken()))
809
- throw new IntermediaryError_1.IntermediaryError("Invalid deposit token used!");
810
- if (data.hasSuccessAction())
811
- throw new IntermediaryError_1.IntermediaryError("Invalid has success action");
812
- if (await this.wrapper._contract.isExpired(this._getInitiator(), data))
813
- throw new IntermediaryError_1.IntermediaryError("Not enough time to claim!");
814
- if (this.wrapper._getHtlcTimeout(data) <= (Date.now() / 1000))
815
- throw new IntermediaryError_1.IntermediaryError("HTLC expires too soon!");
816
- }
817
- /**
818
- * Waits till a lightning network payment is received by the intermediary, and the intermediary
819
- * initiates the swap HTLC on the smart chain side. After the HTLC is initiated you can wait
820
- * for an automatic settlement by the watchtowers with the {@link waitTillClaimed} function,
821
- * or settle manually using the {@link claim} or {@link txsClaim} functions.
822
- *
823
- * If this swap is using an LNURL-withdraw link as input, it automatically posts the
824
- * generated invoice to the LNURL service to pay it.
825
- *
826
- * @param onPaymentReceived Callback as for when the LP reports having received the ln payment
827
- * @param abortSignal Abort signal to stop waiting for payment
828
- * @param checkIntervalSeconds How often to poll the intermediary for answer (default 5 seconds)
829
- */
830
- async waitForPayment(onPaymentReceived, checkIntervalSeconds, abortSignal) {
831
- checkIntervalSeconds ??= 5;
832
- if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
833
- await this.waitTillCommited(checkIntervalSeconds, abortSignal);
834
- }
835
- if (this._state >= FromBTCLNAutoSwapState.CLAIM_COMMITED)
836
- return true;
837
- if (this._state !== FromBTCLNAutoSwapState.PR_CREATED)
838
- throw new Error("Must be in PR_CREATED state!");
839
- const abortController = new AbortController();
840
- if (abortSignal != null)
841
- abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
842
- let save = false;
843
- if (this.lnurl != null && this.lnurlK1 != null && this.lnurlCallback != null && !this.prPosted) {
844
- if (this.pr == null || !this.pr.toLowerCase().startsWith("ln"))
845
- throw new Error("Input lightning network invoice not available, the swap was probably recovered!");
846
- LNURL_1.LNURL.postInvoiceToLNURLWithdraw({ k1: this.lnurlK1, callback: this.lnurlCallback }, this.pr).catch(e => {
847
- this.lnurlFailSignal.abort(e);
848
- });
849
- this.prPosted = true;
850
- save ||= true;
851
- }
852
- if (!this.initiated) {
853
- this.initiated = true;
854
- save ||= true;
855
- }
856
- if (save)
857
- await this._saveAndEmit();
858
- let lnurlFailListener = () => abortController.abort(this.lnurlFailSignal.signal.reason);
859
- this.lnurlFailSignal.signal.addEventListener("abort", lnurlFailListener);
860
- this.lnurlFailSignal.signal.throwIfAborted();
861
- const paymentHash = this.getPaymentHash();
862
- if (paymentHash == null)
863
- throw new Error("Swap payment hash not available, the swap was probably recovered!");
864
- if (this.wrapper._messenger.warmup != null)
865
- await this.wrapper._messenger.warmup().catch(e => {
866
- this.logger.warn("waitForPayment(): Failed to warmup messenger: ", e);
867
- });
868
- if (this._state === FromBTCLNAutoSwapState.PR_CREATED) {
869
- const promises = [
870
- this.waitTillState(FromBTCLNAutoSwapState.PR_PAID, "gte", abortController.signal).then(() => true)
871
- ];
872
- if (this.url != null)
873
- promises.push((async () => {
874
- let resp = { code: IntermediaryAPI_1.InvoiceStatusResponseCodes.PENDING, msg: "" };
875
- while (!abortController.signal.aborted && resp.code === IntermediaryAPI_1.InvoiceStatusResponseCodes.PENDING) {
876
- resp = await IntermediaryAPI_1.IntermediaryAPI.getInvoiceStatus(this.url, paymentHash.toString("hex"));
877
- if (resp.code === IntermediaryAPI_1.InvoiceStatusResponseCodes.PENDING)
878
- await (0, TimeoutUtils_1.timeoutPromise)(checkIntervalSeconds * 1000, abortController.signal);
879
- }
880
- this.lnurlFailSignal.signal.removeEventListener("abort", lnurlFailListener);
881
- abortController.signal.throwIfAborted();
882
- if (resp.code === IntermediaryAPI_1.InvoiceStatusResponseCodes.PAID) {
883
- const swapData = new this.wrapper._swapDataDeserializer(resp.data.data);
884
- return await this._saveRealSwapData(swapData, true);
885
- }
886
- if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
887
- if (resp.code === IntermediaryAPI_1.InvoiceStatusResponseCodes.EXPIRED) {
888
- await this._saveAndEmit(FromBTCLNAutoSwapState.QUOTE_EXPIRED);
889
- }
890
- return false;
891
- }
892
- })());
893
- const paymentResult = await Promise.race(promises);
894
- abortController.abort();
895
- if (!paymentResult)
896
- return false;
897
- if (onPaymentReceived != null)
898
- onPaymentReceived(this.getInputTxId());
899
- }
900
- if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
901
- await this.waitTillCommited(checkIntervalSeconds, abortSignal);
902
- }
903
- return this._state >= FromBTCLNAutoSwapState.CLAIM_COMMITED;
904
- }
905
- //////////////////////////////
906
- //// Commit
907
- /**
908
- * Waits till the intermediary (LP) initiates the swap HTLC escrow on the destination smart chain side
909
- *
910
- * @param checkIntervalSeconds How often to check via a polling watchdog
911
- * @param abortSignal Abort signal
912
- *
913
- * @internal
914
- */
915
- async waitTillCommited(checkIntervalSeconds, abortSignal) {
916
- if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED || this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED)
917
- return Promise.resolve();
918
- if (this._state !== FromBTCLNAutoSwapState.PR_PAID)
919
- throw new Error("Invalid state");
920
- const abortController = (0, Utils_1.extendAbortController)(abortSignal);
921
- let result;
922
- try {
923
- result = await Promise.race([
924
- this.watchdogWaitTillCommited(checkIntervalSeconds, abortController.signal),
925
- this.waitTillState(FromBTCLNAutoSwapState.CLAIM_COMMITED, "gte", abortController.signal).then(() => 0)
926
- ]);
927
- abortController.abort();
928
- }
929
- catch (e) {
930
- abortController.abort();
931
- throw e;
932
- }
933
- if (result === false) {
934
- this.logger.debug("waitTillCommited(): Resolved from watchdog - HTLC expired");
935
- if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
936
- await this._saveAndEmit(FromBTCLNAutoSwapState.EXPIRED);
937
- }
938
- return;
939
- }
940
- if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
941
- this._commitedAt ??= Date.now();
942
- await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_COMMITED);
943
- }
944
- if (result === 0)
945
- this.logger.debug("waitTillCommited(): Resolved from state changed");
946
- if (result === true) {
947
- this.logger.debug("waitTillCommited(): Resolved from watchdog - commited");
948
- if (this.secret != null)
949
- await this._broadcastSecret().catch(e => {
950
- this.logger.error("waitTillCommited(): Error broadcasting swap secret: ", e);
951
- });
952
- }
953
- }
954
- //////////////////////////////
955
- //// Claim
956
- /**
957
- * @inheritDoc
958
- *
959
- * @param _signer Optional signer address to use for claiming the swap, can also be different from the initializer
960
- * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
961
- * was recovered from on-chain data, or the pre-image was generated outside the SDK
962
- *
963
- * @throws {Error} If in invalid state (must be {@link FromBTCLNAutoSwapState.CLAIM_COMMITED})
964
- */
965
- async txsClaim(_signer, secret) {
966
- let address = undefined;
967
- if (_signer != null) {
968
- if (typeof (_signer) === "string") {
969
- address = _signer;
970
- }
971
- else if ((0, base_1.isAbstractSigner)(_signer)) {
972
- address = _signer.getAddress();
973
- }
974
- else {
975
- address = (await this.wrapper._chain.wrapSigner(_signer)).getAddress();
976
- }
977
- }
978
- if (this._state !== FromBTCLNAutoSwapState.CLAIM_COMMITED)
979
- throw new Error("Must be in CLAIM_COMMITED state!");
980
- if (this._data == null)
981
- throw new Error("Unknown data, wrong state?");
982
- const useSecret = secret ?? this.secret;
983
- if (useSecret == null)
984
- throw new Error("Swap secret pre-image not known and not provided, please provide the swap secret pre-image as an argument");
985
- if (!this.isValidSecretPreimage(useSecret))
986
- throw new Error("Invalid swap secret pre-image provided!");
987
- return await this.wrapper._contract.txsClaimWithSecret(address ?? this._getInitiator(), this._data, useSecret, true, true);
988
- }
989
- /**
990
- * @inheritDoc
991
- *
992
- * @param _signer Signer to sign the transactions with, can also be different to the initializer
993
- * @param abortSignal Abort signal to stop waiting for transaction confirmation
994
- * @param onBeforeTxSent
995
- * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
996
- * was recovered from on-chain data, or the pre-image was generated outside the SDK
997
- */
998
- async claim(_signer, abortSignal, onBeforeTxSent, secret) {
999
- const signer = (0, base_1.isAbstractSigner)(_signer) ? _signer : await this.wrapper._chain.wrapSigner(_signer);
1000
- let txCount = 0;
1001
- const txs = await this.txsClaim(_signer, secret);
1002
- const result = await this.wrapper._chain.sendAndConfirm(signer, txs, true, abortSignal, undefined, (txId) => {
1003
- txCount++;
1004
- if (onBeforeTxSent != null && txCount === 1)
1005
- onBeforeTxSent(txId);
1006
- return Promise.resolve();
1007
- });
1008
- this._claimTxId = result[0];
1009
- if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED || this._state === FromBTCLNAutoSwapState.EXPIRED || this._state === FromBTCLNAutoSwapState.FAILED) {
1010
- await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_CLAIMED);
1011
- }
1012
- return result[0];
1013
- }
1014
- /**
1015
- * Waits till the swap is successfully settled (claimed), should be called after sending the claim (settlement)
1016
- * transactions manually to wait till the SDK processes the settlement and updates the swap state accordingly.
1017
- *
1018
- * @param maxWaitTimeSeconds Maximum time in seconds to wait for the swap to be settled
1019
- * @param abortSignal AbortSignal
1020
- * @param secret A swap secret to broadcast to watchtowers, generally only needed if the swap
1021
- * was recovered from on-chain data, or the pre-image was generated outside the SDK
1022
- *
1023
- * @throws {Error} If swap is in invalid state (must be {@link FromBTCLNAutoSwapState.CLAIM_COMMITED})
1024
- * @throws {Error} If the LP refunded sooner than we were able to claim
1025
- * @returns {boolean} whether the swap was claimed in time or not
1026
- */
1027
- async waitTillClaimed(maxWaitTimeSeconds, abortSignal, secret) {
1028
- if (this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED)
1029
- return Promise.resolve(true);
1030
- if (this._state !== FromBTCLNAutoSwapState.CLAIM_COMMITED)
1031
- throw new Error("Invalid state (not CLAIM_COMMITED)");
1032
- if (secret != null) {
1033
- if (!this.isValidSecretPreimage(secret))
1034
- throw new Error("Invalid swap secret pre-image provided!");
1035
- this.secret = secret;
1036
- }
1037
- const abortController = new AbortController();
1038
- if (abortSignal != null)
1039
- abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
1040
- let timedOut = false;
1041
- if (maxWaitTimeSeconds != null) {
1042
- const timeout = setTimeout(() => {
1043
- timedOut = true;
1044
- abortController.abort();
1045
- }, maxWaitTimeSeconds * 1000);
1046
- abortController.signal.addEventListener("abort", () => clearTimeout(timeout));
1047
- }
1048
- let res;
1049
- try {
1050
- res = await Promise.race([
1051
- this.watchdogWaitTillResult(undefined, abortController.signal),
1052
- this.waitTillState(FromBTCLNAutoSwapState.CLAIM_CLAIMED, "eq", abortController.signal).then(() => 0),
1053
- this.waitTillState(FromBTCLNAutoSwapState.EXPIRED, "eq", abortController.signal).then(() => 1),
1054
- ]);
1055
- abortController.abort();
1056
- }
1057
- catch (e) {
1058
- abortController.abort();
1059
- if (timedOut)
1060
- return false;
1061
- throw e;
1062
- }
1063
- if (res === 0) {
1064
- this.logger.debug("waitTillClaimed(): Resolved from state change (CLAIM_CLAIMED)");
1065
- return true;
1066
- }
1067
- if (res === 1) {
1068
- this.logger.debug("waitTillClaimed(): Resolved from state change (EXPIRED)");
1069
- throw new Error("Swap expired during claiming");
1070
- }
1071
- this.logger.debug("waitTillClaimed(): Resolved from watchdog");
1072
- if (res?.type === base_1.SwapCommitStateType.PAID) {
1073
- if (this._state !== FromBTCLNAutoSwapState.CLAIM_CLAIMED) {
1074
- this._claimTxId = await res.getClaimTxId();
1075
- await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_CLAIMED);
1076
- }
1077
- }
1078
- if (res?.type === base_1.SwapCommitStateType.NOT_COMMITED || res?.type === base_1.SwapCommitStateType.EXPIRED) {
1079
- if (this._state !== FromBTCLNAutoSwapState.CLAIM_CLAIMED &&
1080
- this._state !== FromBTCLNAutoSwapState.FAILED) {
1081
- await this._saveAndEmit(FromBTCLNAutoSwapState.FAILED);
1082
- }
1083
- throw new Error("Swap expired during claiming");
1084
- }
1085
- return true;
1086
- }
1087
- //////////////////////////////
1088
- //// LNURL
1089
- /**
1090
- * Whether this swap uses an LNURL-withdraw link
1091
- */
1092
- isLNURL() {
1093
- return this.lnurl != null;
1094
- }
1095
- /**
1096
- * Gets the used LNURL or `null` if this is not an LNURL-withdraw swap
1097
- */
1098
- getLNURL() {
1099
- return this.lnurl ?? null;
1100
- }
1101
- /**
1102
- * Pay the generated lightning network invoice with an LNURL-withdraw link, this
1103
- * is useful when you want to display a lightning payment QR code and also want to
1104
- * allow payments using LNURL-withdraw NFC cards.
1105
- *
1106
- * Note that the swap needs to be created **without** an LNURL to begin with for this function
1107
- * to work. If this swap is already using an LNURL-withdraw link, this function throws.
1108
- */
1109
- async settleWithLNURLWithdraw(lnurl) {
1110
- if (this._state !== FromBTCLNAutoSwapState.PR_CREATED &&
1111
- this._state !== FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED)
1112
- throw new Error("Must be in PR_CREATED state!");
1113
- if (this.lnurl != null)
1114
- throw new Error("Cannot settle LNURL-withdraw swap with different LNURL");
1115
- let lnurlParams;
1116
- if (typeof (lnurl) === "string") {
1117
- const parsedLNURL = await LNURL_1.LNURL.getLNURL(lnurl);
1118
- if (parsedLNURL == null || parsedLNURL.tag !== "withdrawRequest")
1119
- throw new UserError_1.UserError("Invalid LNURL-withdraw to settle the swap");
1120
- lnurlParams = parsedLNURL;
1121
- }
1122
- else {
1123
- lnurlParams = lnurl.params;
1124
- }
1125
- if (this.pr == null || !this.pr.toLowerCase().startsWith("ln"))
1126
- throw new Error("Input lightning network invoice not available, the swap was probably recovered!");
1127
- LNURL_1.LNURL.useLNURLWithdraw(lnurlParams, this.pr).catch(e => this.lnurlFailSignal.abort(e));
1128
- this.lnurl = lnurlParams.url;
1129
- this.lnurlCallback = lnurlParams.callback;
1130
- this.lnurlK1 = lnurlParams.k1;
1131
- this.prPosted = true;
1132
- await this._saveAndEmit();
1133
- }
1134
- //////////////////////////////
1135
- //// Storage
1136
- /**
1137
- * @inheritDoc
1138
- */
1139
- serialize() {
1140
- return {
1141
- ...super.serialize(),
1142
- data: this._data == null ? null : this._data.serialize(),
1143
- commitTxId: this._commitTxId,
1144
- claimTxId: this._claimTxId,
1145
- commitedAt: this._commitedAt,
1146
- btcAmountSwap: this.btcAmountSwap == null ? null : this.btcAmountSwap.toString(10),
1147
- btcAmountGas: this.btcAmountGas == null ? null : this.btcAmountGas.toString(10),
1148
- gasSwapFeeBtc: this.gasSwapFeeBtc == null ? null : this.gasSwapFeeBtc.toString(10),
1149
- gasSwapFee: this.gasSwapFee == null ? null : this.gasSwapFee.toString(10),
1150
- gasPricingInfo: (0, PriceInfoType_1.serializePriceInfoType)(this.gasPricingInfo),
1151
- pr: this.pr,
1152
- secret: this.secret,
1153
- lnurl: this.lnurl,
1154
- lnurlK1: this.lnurlK1,
1155
- lnurlCallback: this.lnurlCallback,
1156
- prPosted: this.prPosted,
1157
- initialSwapData: this.initialSwapData.serialize(),
1158
- usesClaimHashAsId: this.usesClaimHashAsId
1159
- };
1160
- }
1161
- //////////////////////////////
1162
- //// Swap ticks & sync
1163
- /**
1164
- * Checks the swap's state on-chain and compares it to its internal state, updates/changes it according to on-chain
1165
- * data
1166
- *
1167
- * @private
1168
- */
1169
- async syncStateFromChain(quoteDefinitelyExpired, commitStatus) {
1170
- if (this._state === FromBTCLNAutoSwapState.PR_PAID ||
1171
- this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED ||
1172
- this._state === FromBTCLNAutoSwapState.EXPIRED) {
1173
- //Check for expiry before the getCommitStatus to prevent race conditions
1174
- let quoteExpired = false;
1175
- if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
1176
- quoteExpired = quoteDefinitelyExpired ?? await this._verifyQuoteDefinitelyExpired();
1177
- }
1178
- //Check if it's already successfully paid
1179
- commitStatus ??= await this.wrapper._contract.getCommitStatus(this._getInitiator(), this._data);
1180
- if (commitStatus != null && await this._forciblySetOnchainState(commitStatus))
1181
- return true;
1182
- if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
1183
- if (quoteExpired) {
1184
- this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1185
- return true;
1186
- }
1187
- }
1188
- }
1189
- return false;
1190
- }
1191
- /**
1192
- * @inheritDoc
1193
- * @internal
1194
- */
1195
- _shouldFetchOnchainState() {
1196
- return this._state === FromBTCLNAutoSwapState.PR_PAID || this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED || this._state === FromBTCLNAutoSwapState.EXPIRED;
1197
- }
1198
- /**
1199
- * @inheritDoc
1200
- * @internal
1201
- */
1202
- _shouldFetchExpiryStatus() {
1203
- return this._state === FromBTCLNAutoSwapState.PR_PAID;
1204
- }
1205
- /**
1206
- * @inheritDoc
1207
- * @internal
1208
- */
1209
- _shouldCheckIntermediary() {
1210
- return this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1211
- }
1212
- /**
1213
- * @inheritDoc
1214
- * @internal
1215
- */
1216
- async _sync(save, quoteDefinitelyExpired, commitStatus, skipLpCheck) {
1217
- let changed = false;
1218
- if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
1219
- if (this._state !== FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED && this.getQuoteExpiry() < Date.now()) {
1220
- this._state = FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1221
- changed ||= true;
1222
- }
1223
- if (!skipLpCheck)
1224
- try {
1225
- const result = await this._checkIntermediaryPaymentReceived(false);
1226
- if (result !== null)
1227
- changed ||= true;
1228
- }
1229
- catch (e) {
1230
- this.logger.error("_sync(): Failed to synchronize swap, error: ", e);
1231
- }
1232
- if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
1233
- if (await this._verifyQuoteDefinitelyExpired()) {
1234
- this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1235
- changed ||= true;
1236
- }
1237
- }
1238
- }
1239
- if (await this.syncStateFromChain(quoteDefinitelyExpired, commitStatus))
1240
- changed = true;
1241
- if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED) {
1242
- const expired = await this.wrapper._contract.isExpired(this._getInitiator(), this._data);
1243
- if (expired) {
1244
- this._state = FromBTCLNAutoSwapState.EXPIRED;
1245
- changed = true;
1246
- }
1247
- }
1248
- if (save && changed)
1249
- await this._saveAndEmit();
1250
- if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED && this.secret != null)
1251
- await this._broadcastSecret().catch(e => {
1252
- this.logger.error("_sync(): Error when broadcasting swap secret: ", e);
1253
- });
1254
- return changed;
1255
- }
1256
- /**
1257
- * @inheritDoc
1258
- * @internal
1259
- */
1260
- async _forciblySetOnchainState(commitStatus) {
1261
- switch (commitStatus?.type) {
1262
- case base_1.SwapCommitStateType.PAID:
1263
- if (this._claimTxId == null)
1264
- this._claimTxId = await commitStatus.getClaimTxId();
1265
- if (this.secret == null || this.pr == null)
1266
- this._setSwapSecret(await commitStatus.getClaimResult());
1267
- this._state = FromBTCLNAutoSwapState.CLAIM_CLAIMED;
1268
- return true;
1269
- case base_1.SwapCommitStateType.NOT_COMMITED:
1270
- if (this._refundTxId == null && commitStatus.getRefundTxId != null)
1271
- this._refundTxId = await commitStatus.getRefundTxId();
1272
- if (this._refundTxId != null) {
1273
- this._state = FromBTCLNAutoSwapState.FAILED;
1274
- return true;
1275
- }
1276
- break;
1277
- case base_1.SwapCommitStateType.EXPIRED:
1278
- if (this._refundTxId == null && commitStatus.getRefundTxId != null)
1279
- this._refundTxId = await commitStatus.getRefundTxId();
1280
- this._state = this._refundTxId == null ? FromBTCLNAutoSwapState.QUOTE_EXPIRED : FromBTCLNAutoSwapState.FAILED;
1281
- return true;
1282
- case base_1.SwapCommitStateType.COMMITED:
1283
- if (this._state !== FromBTCLNAutoSwapState.CLAIM_COMMITED && this._state !== FromBTCLNAutoSwapState.EXPIRED) {
1284
- this._commitedAt ??= Date.now();
1285
- this._state = FromBTCLNAutoSwapState.CLAIM_COMMITED;
1286
- return true;
1287
- }
1288
- break;
1289
- }
1290
- return false;
1291
- }
1292
- /**
1293
- * Broadcasts the swap secret to the underlying data propagation layer (e.g. Nostr by default)
1294
- *
1295
- * @param noCheckExpiry Whether a swap expiration check should be skipped broadcasting
1296
- * @param secret An optional secret pre-image for the swap to broadcast
1297
- *
1298
- * @internal
1299
- */
1300
- async _broadcastSecret(noCheckExpiry, secret) {
1301
- if (this._state !== FromBTCLNAutoSwapState.CLAIM_COMMITED)
1302
- throw new Error("Must be in CLAIM_COMMITED state to broadcast swap secret!");
1303
- if (this._data == null)
1304
- throw new Error("Unknown data, wrong state?");
1305
- const useSecret = secret ?? this.secret;
1306
- if (useSecret == null)
1307
- throw new Error("Swap secret pre-image not known and not provided, please provide the swap secret pre-image as an argument");
1308
- if (!this.isValidSecretPreimage(useSecret))
1309
- throw new Error("Invalid swap secret pre-image provided!");
1310
- if (!noCheckExpiry) {
1311
- if (await this.wrapper._contract.isExpired(this._getInitiator(), this._data))
1312
- throw new Error("On-chain HTLC already expired!");
1313
- }
1314
- await this.wrapper._messenger.broadcast(new base_1.SwapClaimWitnessMessage(this._data, useSecret));
1315
- }
1316
- /**
1317
- * @inheritDoc
1318
- * @internal
1319
- */
1320
- async _tick(save) {
1321
- switch (this._state) {
1322
- case FromBTCLNAutoSwapState.PR_CREATED:
1323
- if (this.getQuoteExpiry() < Date.now()) {
1324
- this._state = FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1325
- if (save)
1326
- await this._saveAndEmit();
1327
- return true;
1328
- }
1329
- break;
1330
- case FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED:
1331
- if (this.getDefinitiveExpiryTime() < Date.now()) {
1332
- this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1333
- if (save)
1334
- await this._saveAndEmit();
1335
- return true;
1336
- }
1337
- break;
1338
- case FromBTCLNAutoSwapState.PR_PAID:
1339
- case FromBTCLNAutoSwapState.CLAIM_COMMITED:
1340
- const expired = await this.wrapper._contract.isExpired(this._getInitiator(), this._data);
1341
- if (expired) {
1342
- this._state = FromBTCLNAutoSwapState.EXPIRED;
1343
- if (save)
1344
- await this._saveAndEmit();
1345
- return true;
1346
- }
1347
- if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED) {
1348
- //Broadcast the secret over the provided messenger channel
1349
- if (this.broadcastTickCounter === 0 && this.secret != null)
1350
- await this._broadcastSecret(true).catch(e => {
1351
- this.logger.warn("_tick(): Error when broadcasting swap secret: ", e);
1352
- });
1353
- this.broadcastTickCounter = (this.broadcastTickCounter + 1) % 3; //Broadcast every 3rd tick
1354
- }
1355
- break;
1356
- }
1357
- return false;
1358
- }
1359
- /**
1360
- * Forcibly sets the swap secret pre-image from on-chain data
1361
- *
1362
- * @internal
1363
- */
1364
- _setSwapSecret(secret) {
1365
- this.secret = secret;
1366
- if (this.pr == null) {
1367
- this.pr = buffer_1.Buffer.from((0, sha2_1.sha256)(buffer_1.Buffer.from(secret, "hex"))).toString("hex");
1368
- }
1369
- }
1370
- }
1371
- exports.FromBTCLNAutoSwap = FromBTCLNAutoSwap;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FromBTCLNAutoSwap = exports.isFromBTCLNAutoSwapInit = exports.FromBTCLNAutoSwapState = void 0;
4
+ const bolt11_1 = require("@atomiqlabs/bolt11");
5
+ const SwapType_1 = require("../../../../enums/SwapType");
6
+ const base_1 = require("@atomiqlabs/base");
7
+ const buffer_1 = require("buffer");
8
+ const LNURL_1 = require("../../../../lnurl/LNURL");
9
+ const UserError_1 = require("../../../../errors/UserError");
10
+ const IntermediaryAPI_1 = require("../../../../intermediaries/apis/IntermediaryAPI");
11
+ const IntermediaryError_1 = require("../../../../errors/IntermediaryError");
12
+ const Utils_1 = require("../../../../utils/Utils");
13
+ const IEscrowSwap_1 = require("../../IEscrowSwap");
14
+ const FeeType_1 = require("../../../../enums/FeeType");
15
+ const PercentagePPM_1 = require("../../../../types/fees/PercentagePPM");
16
+ const TokenAmount_1 = require("../../../../types/TokenAmount");
17
+ const Token_1 = require("../../../../types/Token");
18
+ const Logger_1 = require("../../../../utils/Logger");
19
+ const TimeoutUtils_1 = require("../../../../utils/TimeoutUtils");
20
+ const LNURLWithdraw_1 = require("../../../../types/lnurl/LNURLWithdraw");
21
+ const PriceInfoType_1 = require("../../../../types/PriceInfoType");
22
+ const sha2_1 = require("@noble/hashes/sha2");
23
+ /**
24
+ * State enum for FromBTCLNAuto swaps
25
+ * @category Swaps/Lightning Smart chain
26
+ */
27
+ var FromBTCLNAutoSwapState;
28
+ (function (FromBTCLNAutoSwapState) {
29
+ /**
30
+ * Swap has failed as the user didn't settle the HTLC on the destination before expiration
31
+ */
32
+ FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["FAILED"] = -4] = "FAILED";
33
+ /**
34
+ * Swap has expired for good and there is no way how it can be executed anymore
35
+ */
36
+ FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["QUOTE_EXPIRED"] = -3] = "QUOTE_EXPIRED";
37
+ /**
38
+ * A swap is almost expired, and it should be presented to the user as expired, though
39
+ * there is still a chance that it will be processed
40
+ */
41
+ FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["QUOTE_SOFT_EXPIRED"] = -2] = "QUOTE_SOFT_EXPIRED";
42
+ /**
43
+ * Swap HTLC on the destination chain has expired, it is not safe anymore to settle (claim) the
44
+ * swap on the destination smart chain.
45
+ */
46
+ FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["EXPIRED"] = -1] = "EXPIRED";
47
+ /**
48
+ * Swap quote was created, use {@link FromBTCLNAutoSwap.getAddress} or {@link FromBTCLNAutoSwap.getHyperlink}
49
+ * to get the bolt11 lightning network invoice to pay to initiate the swap, then use the
50
+ * {@link FromBTCLNAutoSwap.waitForPayment} to wait till the lightning network payment is received
51
+ * by the intermediary (LP) and the destination HTLC escrow is created
52
+ */
53
+ FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["PR_CREATED"] = 0] = "PR_CREATED";
54
+ /**
55
+ * Lightning network payment has been received by the intermediary (LP), but the destination chain
56
+ * HTLC escrow hasn't been created yet. Use {@link FromBTCLNAutoSwap.waitForPayment} to continue waiting
57
+ * till the destination HTLC escrow is created.
58
+ */
59
+ FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["PR_PAID"] = 1] = "PR_PAID";
60
+ /**
61
+ * Swap escrow HTLC has been created on the destination chain, wait for automatic settlement by the watchtowers
62
+ * using the {@link FromBTCLNAutoSwap.waitTillClaimed} function or settle manually using the
63
+ * {@link FromBTCLNAutoSwap.claim} or {@link FromBTCLNAutoSwap.txsClaim} function.
64
+ */
65
+ FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["CLAIM_COMMITED"] = 2] = "CLAIM_COMMITED";
66
+ /**
67
+ * Swap successfully settled and funds received on the destination chain
68
+ */
69
+ FromBTCLNAutoSwapState[FromBTCLNAutoSwapState["CLAIM_CLAIMED"] = 3] = "CLAIM_CLAIMED";
70
+ })(FromBTCLNAutoSwapState = exports.FromBTCLNAutoSwapState || (exports.FromBTCLNAutoSwapState = {}));
71
+ const FromBTCLNAutoSwapStateDescription = {
72
+ [FromBTCLNAutoSwapState.FAILED]: "Swap has failed as the user didn't settle the HTLC on the destination before expiration",
73
+ [FromBTCLNAutoSwapState.QUOTE_EXPIRED]: "Swap has expired for good and there is no way how it can be executed anymore",
74
+ [FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED]: "A swap is expired, though there is still a chance that it will be processed",
75
+ [FromBTCLNAutoSwapState.EXPIRED]: "Swap HTLC on the destination chain has expired, it is not safe anymore to settle (claim) the swap on the destination smart chain.",
76
+ [FromBTCLNAutoSwapState.PR_CREATED]: "Swap quote was created, pay the bolt11 lightning network invoice to initiate the swap, then wait till the lightning network payment is received by the intermediary (LP) and the destination HTLC escrow is created",
77
+ [FromBTCLNAutoSwapState.PR_PAID]: "Lightning network payment has been received by the intermediary (LP), but the destination chain HTLC escrow hasn't been created yet. Continue waiting till the destination HTLC escrow is created.",
78
+ [FromBTCLNAutoSwapState.CLAIM_COMMITED]: "Swap escrow HTLC has been created on the destination chain, wait for automatic settlement by the watchtowers or settle manually.",
79
+ [FromBTCLNAutoSwapState.CLAIM_CLAIMED]: "Swap successfully settled and funds received on the destination chain"
80
+ };
81
+ function isFromBTCLNAutoSwapInit(obj) {
82
+ return (obj.pr == null || typeof obj.pr === "string") &&
83
+ (obj.secret == null || typeof obj.secret === "string") &&
84
+ (obj.btcAmountSwap == null || typeof obj.btcAmountSwap === "bigint") &&
85
+ (obj.btcAmountGas == null || typeof obj.btcAmountGas === "bigint") &&
86
+ typeof obj.gasSwapFeeBtc === "bigint" &&
87
+ typeof obj.gasSwapFee === "bigint" &&
88
+ (obj.gasPricingInfo == null || (0, PriceInfoType_1.isPriceInfoType)(obj.gasPricingInfo)) &&
89
+ (obj.lnurl == null || typeof (obj.lnurl) === "string") &&
90
+ (obj.lnurlK1 == null || typeof (obj.lnurlK1) === "string") &&
91
+ (obj.lnurlCallback == null || typeof (obj.lnurlCallback) === "string") &&
92
+ (0, IEscrowSwap_1.isIEscrowSwapInit)(obj);
93
+ }
94
+ exports.isFromBTCLNAutoSwapInit = isFromBTCLNAutoSwapInit;
95
+ /**
96
+ * New escrow based (HTLC) swaps for Bitcoin Lightning -> Smart chain swaps not requiring manual settlement on
97
+ * the destination by the user, and instead letting the LP initiate the escrow. Permissionless watchtower network
98
+ * handles the claiming of HTLC, with the swap secret broadcasted over Nostr. Also adds a possibility for the user
99
+ * to receive a native token on the destination chain as part of the swap (a "gas drop" feature).
100
+ *
101
+ * @category Swaps/Lightning → Smart chain
102
+ */
103
+ class FromBTCLNAutoSwap extends IEscrowSwap_1.IEscrowSwap {
104
+ /**
105
+ * Sets the LNURL data for the swap
106
+ *
107
+ * @internal
108
+ */
109
+ _setLNURLData(lnurl, lnurlK1, lnurlCallback) {
110
+ this.lnurl = lnurl;
111
+ this.lnurlK1 = lnurlK1;
112
+ this.lnurlCallback = lnurlCallback;
113
+ }
114
+ constructor(wrapper, initOrObject) {
115
+ if (isFromBTCLNAutoSwapInit(initOrObject) && initOrObject.url != null)
116
+ initOrObject.url += "/frombtcln_auto";
117
+ super(wrapper, initOrObject);
118
+ this.TYPE = SwapType_1.SwapType.FROM_BTCLN_AUTO;
119
+ /**
120
+ * @internal
121
+ */
122
+ this.swapStateName = (state) => FromBTCLNAutoSwapState[state];
123
+ /**
124
+ * @internal
125
+ */
126
+ this.swapStateDescription = FromBTCLNAutoSwapStateDescription;
127
+ /**
128
+ * @internal
129
+ */
130
+ this.inputToken = Token_1.BitcoinTokens.BTCLN;
131
+ this.lnurlFailSignal = new AbortController();
132
+ this.prPosted = false;
133
+ this.broadcastTickCounter = 0;
134
+ if (isFromBTCLNAutoSwapInit(initOrObject)) {
135
+ this._state = FromBTCLNAutoSwapState.PR_CREATED;
136
+ this.pr = initOrObject.pr;
137
+ this.secret = initOrObject.secret;
138
+ this.initialSwapData = initOrObject.initialSwapData;
139
+ this.btcAmountSwap = initOrObject.btcAmountSwap;
140
+ this.btcAmountGas = initOrObject.btcAmountGas;
141
+ this.gasSwapFeeBtc = initOrObject.gasSwapFeeBtc;
142
+ this.gasSwapFee = initOrObject.gasSwapFee;
143
+ this.gasPricingInfo = initOrObject.gasPricingInfo;
144
+ this.lnurl = initOrObject.lnurl;
145
+ this.lnurlK1 = initOrObject.lnurlK1;
146
+ this.lnurlCallback = initOrObject.lnurlCallback;
147
+ this.usesClaimHashAsId = true;
148
+ }
149
+ else {
150
+ this.pr = initOrObject.pr;
151
+ this.secret = initOrObject.secret;
152
+ if (initOrObject.initialSwapData == null) {
153
+ this.initialSwapData = this._data;
154
+ }
155
+ else {
156
+ this.initialSwapData = base_1.SwapData.deserialize(initOrObject.initialSwapData);
157
+ }
158
+ this.btcAmountSwap = (0, Utils_1.toBigInt)(initOrObject.btcAmountSwap);
159
+ this.btcAmountGas = (0, Utils_1.toBigInt)(initOrObject.btcAmountGas);
160
+ this.gasSwapFeeBtc = (0, Utils_1.toBigInt)(initOrObject.gasSwapFeeBtc);
161
+ this.gasSwapFee = (0, Utils_1.toBigInt)(initOrObject.gasSwapFee);
162
+ this.gasPricingInfo = (0, PriceInfoType_1.deserializePriceInfoType)(initOrObject.gasPricingInfo);
163
+ this._commitTxId = initOrObject.commitTxId;
164
+ this._claimTxId = initOrObject.claimTxId;
165
+ this._commitedAt = initOrObject.commitedAt;
166
+ this.lnurl = initOrObject.lnurl;
167
+ this.lnurlK1 = initOrObject.lnurlK1;
168
+ this.lnurlCallback = initOrObject.lnurlCallback;
169
+ this.prPosted = initOrObject.prPosted;
170
+ this.usesClaimHashAsId = initOrObject.usesClaimHashAsId ?? false;
171
+ }
172
+ this.tryRecomputeSwapPrice();
173
+ this.logger = (0, Logger_1.getLogger)("FromBTCLNAuto(" + this.getIdentifierHashString() + "): ");
174
+ }
175
+ /**
176
+ * @inheritDoc
177
+ * @internal
178
+ */
179
+ getSwapData() {
180
+ return this._data ?? this.initialSwapData;
181
+ }
182
+ /**
183
+ * @inheritDoc
184
+ * @internal
185
+ */
186
+ upgradeVersion() { }
187
+ /**
188
+ * @inheritDoc
189
+ * @internal
190
+ */
191
+ tryRecomputeSwapPrice() {
192
+ if (this.pricingInfo == null || this.btcAmountSwap == null)
193
+ return;
194
+ if (this.pricingInfo.swapPriceUSatPerToken == null) {
195
+ const priceUsdPerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
196
+ this.pricingInfo = this.wrapper._prices.recomputePriceInfoReceive(this.chainIdentifier, this.btcAmountSwap, this.pricingInfo.satsBaseFee, this.pricingInfo.feePPM, this.getOutputAmountWithoutFee(), this.getSwapData().getToken());
197
+ this.pricingInfo.realPriceUsdPerBitcoin = priceUsdPerBtc;
198
+ }
199
+ }
200
+ //////////////////////////////
201
+ //// Pricing
202
+ /**
203
+ * @inheritDoc
204
+ */
205
+ async refreshPriceData() {
206
+ if (this.pricingInfo == null || this.btcAmountSwap == null)
207
+ return;
208
+ const usdPricePerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
209
+ this.pricingInfo = await this.wrapper._prices.isValidAmountReceive(this.chainIdentifier, this.btcAmountSwap, this.pricingInfo.satsBaseFee, this.pricingInfo.feePPM, this.getOutputAmountWithoutFee(), this.getSwapData().getToken(), undefined, undefined, this.swapFeeBtc);
210
+ this.pricingInfo.realPriceUsdPerBitcoin = usdPricePerBtc;
211
+ }
212
+ //////////////////////////////
213
+ //// Getters & utils
214
+ /**
215
+ * @inheritDoc
216
+ * @internal
217
+ */
218
+ _getEscrowHash() {
219
+ //Use claim hash in case the data is not yet known
220
+ return this._data == null ? this.initialSwapData?.getClaimHash() : this._data?.getEscrowHash();
221
+ }
222
+ /**
223
+ * @inheritDoc
224
+ * @internal
225
+ */
226
+ _getInitiator() {
227
+ return this.getSwapData().getClaimer();
228
+ }
229
+ /**
230
+ * @inheritDoc
231
+ */
232
+ getId() {
233
+ return this.getIdentifierHashString();
234
+ }
235
+ /**
236
+ * @inheritDoc
237
+ */
238
+ getOutputAddress() {
239
+ return this._getInitiator();
240
+ }
241
+ /**
242
+ * @inheritDoc
243
+ */
244
+ getOutputTxId() {
245
+ return this._claimTxId ?? null;
246
+ }
247
+ /**
248
+ * @inheritDoc
249
+ */
250
+ requiresAction() {
251
+ return this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED;
252
+ }
253
+ /**
254
+ * @inheritDoc
255
+ * @internal
256
+ */
257
+ getIdentifierHashString() {
258
+ const id = this.usesClaimHashAsId
259
+ ? this.getClaimHash()
260
+ : this.getPaymentHash().toString("hex");
261
+ if (this._randomNonce == null)
262
+ return id;
263
+ return id + this._randomNonce;
264
+ }
265
+ /**
266
+ * Returns the payment hash of the swap and lightning network invoice, or `null` if not known (i.e. if
267
+ * the swap was recovered from on-chain data, the payment hash might not be known)
268
+ *
269
+ * @internal
270
+ */
271
+ getPaymentHash() {
272
+ if (this.pr == null)
273
+ return null;
274
+ if (this.pr.toLowerCase().startsWith("ln")) {
275
+ const parsed = (0, bolt11_1.decode)(this.pr);
276
+ if (parsed.tagsObject.payment_hash == null)
277
+ throw new Error("Swap invoice has no payment hash field!");
278
+ return buffer_1.Buffer.from(parsed.tagsObject.payment_hash, "hex");
279
+ }
280
+ return buffer_1.Buffer.from(this.pr, "hex");
281
+ }
282
+ /**
283
+ * @inheritDoc
284
+ */
285
+ getInputAddress() {
286
+ return this.lnurl ?? this.pr ?? null;
287
+ }
288
+ /**
289
+ * @inheritDoc
290
+ */
291
+ getInputTxId() {
292
+ const paymentHash = this.getPaymentHash();
293
+ if (paymentHash == null)
294
+ return null;
295
+ return paymentHash.toString("hex");
296
+ }
297
+ /**
298
+ * Returns the lightning network BOLT11 invoice that needs to be paid as an input to the swap
299
+ */
300
+ getAddress() {
301
+ return this.pr ?? "";
302
+ }
303
+ /**
304
+ * @inheritDoc
305
+ */
306
+ getHyperlink() {
307
+ return this.pr == null ? "" : "lightning:" + this.pr.toUpperCase();
308
+ }
309
+ /**
310
+ * Returns the timeout time (in UNIX milliseconds) when the swap will definitelly be considered as expired
311
+ * if the LP doesn't make it expired sooner
312
+ */
313
+ getDefinitiveExpiryTime() {
314
+ if (this.pr == null || !this.pr.toLowerCase().startsWith("ln"))
315
+ return 0;
316
+ const decoded = (0, bolt11_1.decode)(this.pr);
317
+ if (decoded.tagsObject.min_final_cltv_expiry == null)
318
+ throw new Error("Swap invoice doesn't contain final ctlv delta field!");
319
+ if (decoded.timeExpireDate == null)
320
+ throw new Error("Swap invoice doesn't contain expiry date field!");
321
+ const finalCltvExpiryDelta = decoded.tagsObject.min_final_cltv_expiry ?? 144;
322
+ const finalCltvExpiryDelay = finalCltvExpiryDelta * this.wrapper._options.bitcoinBlocktime * this.wrapper._options.safetyFactor;
323
+ return (decoded.timeExpireDate + finalCltvExpiryDelay) * 1000;
324
+ }
325
+ /**
326
+ * Returns timeout time (in UNIX milliseconds) when the swap htlc will expire
327
+ */
328
+ getHtlcTimeoutTime() {
329
+ return this._data == null ? null : Number(this.wrapper._getHtlcTimeout(this._data)) * 1000;
330
+ }
331
+ /**
332
+ * @inheritDoc
333
+ */
334
+ isFinished() {
335
+ return this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED || this._state === FromBTCLNAutoSwapState.QUOTE_EXPIRED || this._state === FromBTCLNAutoSwapState.FAILED;
336
+ }
337
+ /**
338
+ * @inheritDoc
339
+ */
340
+ isClaimable() {
341
+ return this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED;
342
+ }
343
+ /**
344
+ * @inheritDoc
345
+ */
346
+ isSuccessful() {
347
+ return this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED;
348
+ }
349
+ /**
350
+ * @inheritDoc
351
+ */
352
+ isFailed() {
353
+ return this._state === FromBTCLNAutoSwapState.FAILED || this._state === FromBTCLNAutoSwapState.EXPIRED;
354
+ }
355
+ /**
356
+ * @inheritDoc
357
+ */
358
+ isInProgress() {
359
+ return (this._state === FromBTCLNAutoSwapState.PR_CREATED && this.initiated) ||
360
+ (this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED && this.initiated) ||
361
+ this._state === FromBTCLNAutoSwapState.PR_PAID ||
362
+ this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED;
363
+ }
364
+ /**
365
+ * @inheritDoc
366
+ */
367
+ isQuoteExpired() {
368
+ return this._state === FromBTCLNAutoSwapState.QUOTE_EXPIRED;
369
+ }
370
+ /**
371
+ * @inheritDoc
372
+ */
373
+ isQuoteSoftExpired() {
374
+ return this._state === FromBTCLNAutoSwapState.QUOTE_EXPIRED;
375
+ }
376
+ /**
377
+ * @inheritDoc
378
+ */
379
+ _verifyQuoteDefinitelyExpired() {
380
+ return Promise.resolve(this.getDefinitiveExpiryTime() < Date.now());
381
+ }
382
+ /**
383
+ * @inheritDoc
384
+ */
385
+ _verifyQuoteValid() {
386
+ return Promise.resolve(this.getQuoteExpiry() > Date.now());
387
+ }
388
+ //////////////////////////////
389
+ //// Amounts & fees
390
+ /**
391
+ * Returns the satoshi amount of the lightning network invoice, or `null` if the lightning network
392
+ * invoice is not known (i.e. when the swap was recovered from on-chain data, the paid invoice
393
+ * cannot be recovered because it is purely off-chain)
394
+ *
395
+ * @internal
396
+ */
397
+ getLightningInvoiceSats() {
398
+ if (this.pr == null || !this.pr.toLowerCase().startsWith("ln"))
399
+ return null;
400
+ const parsed = (0, bolt11_1.decode)(this.pr);
401
+ if (parsed.millisatoshis == null)
402
+ throw new Error("Swap invoice doesn't contain msat amount field!");
403
+ return (BigInt(parsed.millisatoshis) + 999n) / 1000n;
404
+ }
405
+ /**
406
+ * Returns the watchtower fee paid in BTC satoshis, or null if known (i.e. if the swap was recovered from
407
+ * on-chain data)
408
+ *
409
+ * @protected
410
+ */
411
+ getWatchtowerFeeAmountBtc() {
412
+ if (this.btcAmountGas == null)
413
+ return null;
414
+ return (this.btcAmountGas - this.gasSwapFeeBtc) * this.getSwapData().getClaimerBounty() / this.getSwapData().getTotalDeposit();
415
+ }
416
+ /**
417
+ * Returns the input amount for the actual swap (excluding the input amount used to cover the "gas drop"
418
+ * part of the swap), excluding fees
419
+ *
420
+ * @internal
421
+ */
422
+ getInputSwapAmountWithoutFee() {
423
+ if (this.btcAmountSwap == null)
424
+ return null;
425
+ return this.btcAmountSwap - this.swapFeeBtc;
426
+ }
427
+ /**
428
+ * Returns the input amount purely for the "gas drop" part of the swap (this much BTC in sats will be
429
+ * swapped into the native gas token on the destination chain), excluding fees
430
+ *
431
+ * @internal
432
+ */
433
+ getInputGasAmountWithoutFee() {
434
+ if (this.btcAmountGas == null)
435
+ return null;
436
+ return this.btcAmountGas - this.gasSwapFeeBtc;
437
+ }
438
+ /**
439
+ * Get total btc amount in sats on the input, excluding the swap fee and watchtower fee
440
+ *
441
+ * @internal
442
+ */
443
+ getInputAmountWithoutFee() {
444
+ if (this.btcAmountGas == null || this.btcAmountSwap == null)
445
+ return null;
446
+ return this.getInputSwapAmountWithoutFee() + this.getInputGasAmountWithoutFee() - this.getWatchtowerFeeAmountBtc();
447
+ }
448
+ /**
449
+ * Returns the "would be" output amount if the swap charged no swap fee
450
+ *
451
+ * @internal
452
+ */
453
+ getOutputAmountWithoutFee() {
454
+ return this.getSwapData().getAmount() + this.swapFee;
455
+ }
456
+ /**
457
+ * @inheritDoc
458
+ */
459
+ getInputToken() {
460
+ return Token_1.BitcoinTokens.BTCLN;
461
+ }
462
+ /**
463
+ * @inheritDoc
464
+ */
465
+ getInput() {
466
+ return (0, TokenAmount_1.toTokenAmount)(this.getLightningInvoiceSats(), this.inputToken, this.wrapper._prices, this.pricingInfo);
467
+ }
468
+ /**
469
+ * @inheritDoc
470
+ */
471
+ getInputWithoutFee() {
472
+ return (0, TokenAmount_1.toTokenAmount)(this.getInputAmountWithoutFee(), this.inputToken, this.wrapper._prices, this.pricingInfo);
473
+ }
474
+ /**
475
+ * @inheritDoc
476
+ */
477
+ getOutputToken() {
478
+ return this.wrapper._tokens[this.getSwapData().getToken()];
479
+ }
480
+ /**
481
+ * @inheritDoc
482
+ */
483
+ getOutput() {
484
+ return (0, TokenAmount_1.toTokenAmount)(this.getSwapData().getAmount(), this.wrapper._tokens[this.getSwapData().getToken()], this.wrapper._prices, this.pricingInfo);
485
+ }
486
+ /**
487
+ * @inheritDoc
488
+ */
489
+ getGasDropOutput() {
490
+ return (0, TokenAmount_1.toTokenAmount)(this.getSwapData().getSecurityDeposit() - this.getSwapData().getClaimerBounty(), this.wrapper._tokens[this.getSwapData().getDepositToken()], this.wrapper._prices, this.gasPricingInfo);
491
+ }
492
+ /**
493
+ * Returns the swap fee charged by the intermediary (LP) on this swap
494
+ *
495
+ * @internal
496
+ */
497
+ getSwapFee() {
498
+ if (this.pricingInfo == null)
499
+ throw new Error("No pricing info known, cannot estimate fee!");
500
+ const outputToken = this.wrapper._tokens[this.getSwapData().getToken()];
501
+ const gasSwapFeeInOutputToken = this.gasSwapFeeBtc
502
+ * (10n ** BigInt(outputToken.decimals))
503
+ * 1000000n
504
+ / this.pricingInfo.swapPriceUSatPerToken;
505
+ const feeWithoutBaseFee = this.gasSwapFeeBtc + this.swapFeeBtc - this.pricingInfo.satsBaseFee;
506
+ const inputSats = this.getLightningInvoiceSats();
507
+ const swapFeePPM = inputSats != null
508
+ ? feeWithoutBaseFee * 1000000n / (inputSats - this.swapFeeBtc - this.gasSwapFeeBtc)
509
+ : 0n;
510
+ const amountInSrcToken = (0, TokenAmount_1.toTokenAmount)(this.swapFeeBtc + this.gasSwapFeeBtc, Token_1.BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo);
511
+ return {
512
+ amountInSrcToken,
513
+ amountInDstToken: (0, TokenAmount_1.toTokenAmount)(this.swapFee + gasSwapFeeInOutputToken, outputToken, this.wrapper._prices, this.pricingInfo),
514
+ currentUsdValue: amountInSrcToken.currentUsdValue,
515
+ pastUsdValue: amountInSrcToken.pastUsdValue,
516
+ usdValue: amountInSrcToken.usdValue,
517
+ composition: {
518
+ base: (0, TokenAmount_1.toTokenAmount)(this.pricingInfo.satsBaseFee, Token_1.BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo),
519
+ percentage: (0, PercentagePPM_1.ppmToPercentage)(swapFeePPM)
520
+ }
521
+ };
522
+ }
523
+ /**
524
+ * Returns the fee to be paid to watchtowers on the destination chain to automatically
525
+ * process and settle this swap without requiring any user interaction
526
+ *
527
+ * @internal
528
+ */
529
+ getWatchtowerFee() {
530
+ if (this.pricingInfo == null)
531
+ throw new Error("No pricing info known, cannot estimate fee!");
532
+ const btcWatchtowerFee = this.getWatchtowerFeeAmountBtc();
533
+ const outputToken = this.wrapper._tokens[this.getSwapData().getToken()];
534
+ const watchtowerFeeInOutputToken = btcWatchtowerFee == null ? 0n : btcWatchtowerFee
535
+ * (10n ** BigInt(outputToken.decimals))
536
+ * 1000000n
537
+ / this.pricingInfo.swapPriceUSatPerToken;
538
+ const amountInSrcToken = (0, TokenAmount_1.toTokenAmount)(btcWatchtowerFee, Token_1.BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo);
539
+ return {
540
+ amountInSrcToken,
541
+ amountInDstToken: (0, TokenAmount_1.toTokenAmount)(watchtowerFeeInOutputToken, outputToken, this.wrapper._prices, this.pricingInfo),
542
+ currentUsdValue: amountInSrcToken.currentUsdValue,
543
+ usdValue: amountInSrcToken.usdValue,
544
+ pastUsdValue: amountInSrcToken.pastUsdValue
545
+ };
546
+ }
547
+ /**
548
+ * @inheritDoc
549
+ */
550
+ getFee() {
551
+ const swapFee = this.getSwapFee();
552
+ const watchtowerFee = this.getWatchtowerFee();
553
+ const amountInSrcToken = (0, TokenAmount_1.toTokenAmount)(swapFee.amountInSrcToken.rawAmount + watchtowerFee.amountInSrcToken.rawAmount, Token_1.BitcoinTokens.BTCLN, this.wrapper._prices, this.pricingInfo);
554
+ return {
555
+ amountInSrcToken,
556
+ amountInDstToken: (0, TokenAmount_1.toTokenAmount)(swapFee.amountInDstToken.rawAmount + watchtowerFee.amountInDstToken.rawAmount, this.wrapper._tokens[this.getSwapData().getToken()], this.wrapper._prices, this.pricingInfo),
557
+ currentUsdValue: amountInSrcToken.currentUsdValue,
558
+ usdValue: amountInSrcToken.usdValue,
559
+ pastUsdValue: amountInSrcToken.pastUsdValue
560
+ };
561
+ }
562
+ /**
563
+ * @inheritDoc
564
+ */
565
+ getFeeBreakdown() {
566
+ return [
567
+ {
568
+ type: FeeType_1.FeeType.SWAP,
569
+ fee: this.getSwapFee()
570
+ },
571
+ {
572
+ type: FeeType_1.FeeType.NETWORK_OUTPUT,
573
+ fee: this.getWatchtowerFee()
574
+ }
575
+ ];
576
+ }
577
+ isValidSecretPreimage(secret) {
578
+ const paymentHash = buffer_1.Buffer.from((0, sha2_1.sha256)(buffer_1.Buffer.from(secret, "hex")));
579
+ const claimHash = this.wrapper._contract.getHashForHtlc(paymentHash).toString("hex");
580
+ return this.getSwapData().getClaimHash() === claimHash;
581
+ }
582
+ /**
583
+ * Sets the secret preimage for the swap, in case it is not known already
584
+ *
585
+ * @param secret Secret preimage that matches the expected payment hash
586
+ *
587
+ * @throws {Error} If an invalid secret preimage is provided
588
+ */
589
+ setSecretPreimage(secret) {
590
+ if (!this.isValidSecretPreimage(secret))
591
+ throw new Error("Invalid secret preimage provided, hash doesn't match!");
592
+ this.secret = secret;
593
+ }
594
+ /**
595
+ * Returns whether the secret preimage for this swap is known
596
+ */
597
+ hasSecretPreimage() {
598
+ return this.secret != null;
599
+ }
600
+ //////////////////////////////
601
+ //// Execution
602
+ /**
603
+ * Executes the swap with the provided bitcoin lightning network wallet or LNURL
604
+ *
605
+ * @param walletOrLnurlWithdraw Bitcoin lightning wallet to use to pay the lightning network invoice, or an LNURL-withdraw
606
+ * link, wallet is not required and the LN invoice can be paid externally as well (just pass null or undefined here)
607
+ * @param callbacks Callbacks to track the progress of the swap
608
+ * @param options Optional options for the swap like AbortSignal, and timeouts/intervals
609
+ * @param options.secret A swap secret to broadcast to watchtowers, generally only needed if the swap
610
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
611
+ *
612
+ * @returns {boolean} Whether a swap was settled automatically by swap watchtowers or requires manual claim by the
613
+ * user, in case `false` is returned the user should call `swap.claim()` to settle the swap on the destination manually
614
+ */
615
+ async execute(walletOrLnurlWithdraw, callbacks, options) {
616
+ if (this._state === FromBTCLNAutoSwapState.FAILED)
617
+ throw new Error("Swap failed!");
618
+ if (this._state === FromBTCLNAutoSwapState.EXPIRED)
619
+ throw new Error("Swap HTLC expired!");
620
+ if (this._state === FromBTCLNAutoSwapState.QUOTE_EXPIRED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED)
621
+ throw new Error("Swap quote expired!");
622
+ if (this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED)
623
+ throw new Error("Swap already settled!");
624
+ let abortSignal = options?.abortSignal;
625
+ if (this._state === FromBTCLNAutoSwapState.PR_CREATED) {
626
+ if (walletOrLnurlWithdraw != null && this.lnurl == null) {
627
+ if (this.pr == null || !this.pr.toLowerCase().startsWith("ln"))
628
+ throw new Error("Input lightning network invoice not available, the swap was probably recovered!");
629
+ if (typeof (walletOrLnurlWithdraw) === "string" || (0, LNURLWithdraw_1.isLNURLWithdraw)(walletOrLnurlWithdraw)) {
630
+ await this.settleWithLNURLWithdraw(walletOrLnurlWithdraw);
631
+ }
632
+ else {
633
+ const paymentPromise = walletOrLnurlWithdraw.payInvoice(this.pr);
634
+ const abortController = new AbortController();
635
+ paymentPromise.catch(e => abortController.abort(e));
636
+ if (options?.abortSignal != null)
637
+ options.abortSignal.addEventListener("abort", () => abortController.abort(options?.abortSignal?.reason));
638
+ abortSignal = abortController.signal;
639
+ }
640
+ }
641
+ }
642
+ if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.PR_PAID) {
643
+ const paymentSuccess = await this.waitForPayment(callbacks?.onSourceTransactionReceived, options?.lightningTxCheckIntervalSeconds, abortSignal);
644
+ if (!paymentSuccess)
645
+ throw new Error("Failed to receive lightning network payment");
646
+ }
647
+ if (this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED)
648
+ return true;
649
+ if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED) {
650
+ if (this.secret == null && options?.secret == null)
651
+ throw new Error("Tried to wait till settlement, but no secret pre-image is known, please pass the secret pre-image as an argument!");
652
+ const success = await this.waitTillClaimed(options?.maxWaitTillAutomaticSettlementSeconds ?? 60, options?.abortSignal, options?.secret);
653
+ if (success && callbacks?.onSwapSettled != null)
654
+ callbacks.onSwapSettled(this.getOutputTxId());
655
+ return success;
656
+ }
657
+ throw new Error("Invalid state reached!");
658
+ }
659
+ /**
660
+ * @inheritDoc
661
+ */
662
+ async txsExecute() {
663
+ if (this._state === FromBTCLNAutoSwapState.PR_CREATED) {
664
+ if (!await this._verifyQuoteValid())
665
+ throw new Error("Quote already expired or close to expiry!");
666
+ return [
667
+ {
668
+ name: "Payment",
669
+ description: "Initiates the swap by paying up the lightning network invoice",
670
+ chain: "LIGHTNING",
671
+ txs: [
672
+ {
673
+ type: "BOLT11_PAYMENT_REQUEST",
674
+ address: this.getAddress(),
675
+ hyperlink: this.getHyperlink()
676
+ }
677
+ ]
678
+ }
679
+ ];
680
+ }
681
+ throw new Error("Invalid swap state to obtain execution txns, required PR_CREATED");
682
+ }
683
+ /**
684
+ *
685
+ * @param options.manualSettlementSmartChainSigner Optional smart chain signer to create a manual claim (settlement) transaction
686
+ * @param options.maxWaitTillAutomaticSettlementSeconds Maximum time to wait for an automatic settlement after
687
+ * the bitcoin transaction is confirmed (defaults to 60 seconds)
688
+ * @param options.secret A swap secret to broadcast to watchtowers, generally only needed if the swap
689
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
690
+ */
691
+ async getCurrentActions(options) {
692
+ if (options?.secret != null)
693
+ this.setSecretPreimage(options.secret);
694
+ if (this._state === FromBTCLNAutoSwapState.PR_CREATED) {
695
+ try {
696
+ return await this.txsExecute();
697
+ }
698
+ catch (e) { }
699
+ }
700
+ if (this.isClaimable()) {
701
+ if (this._commitedAt == null ||
702
+ options?.maxWaitTillAutomaticSettlementSeconds === 0 ||
703
+ (Date.now() - this._commitedAt) > (options?.maxWaitTillAutomaticSettlementSeconds ?? 60) * 1000) {
704
+ return [{
705
+ name: "Claim",
706
+ description: "Manually settle (claim) the swap on the destination smart chain",
707
+ chain: this.chainIdentifier,
708
+ txs: await this.txsClaim(options?.manualSettlementSmartChainSigner)
709
+ }];
710
+ }
711
+ }
712
+ return [];
713
+ }
714
+ //////////////////////////////
715
+ //// Payment
716
+ /**
717
+ * Checks whether the LP received the LN payment
718
+ *
719
+ * @param save If the new swap state should be saved
720
+ *
721
+ * @internal
722
+ */
723
+ async _checkIntermediaryPaymentReceived(save = true) {
724
+ if (this._state === FromBTCLNAutoSwapState.PR_PAID ||
725
+ this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED ||
726
+ this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED ||
727
+ this._state === FromBTCLNAutoSwapState.FAILED ||
728
+ this._state === FromBTCLNAutoSwapState.EXPIRED)
729
+ return true;
730
+ if (this._state === FromBTCLNAutoSwapState.QUOTE_EXPIRED)
731
+ return false;
732
+ if (this.url == null)
733
+ return false;
734
+ const paymentHash = this.getPaymentHash();
735
+ if (paymentHash == null)
736
+ throw new Error("Failed to check LP payment received, payment hash not known (probably recovered swap?)");
737
+ const resp = await IntermediaryAPI_1.IntermediaryAPI.getInvoiceStatus(this.url, paymentHash.toString("hex"));
738
+ switch (resp.code) {
739
+ case IntermediaryAPI_1.InvoiceStatusResponseCodes.PAID:
740
+ const data = new this.wrapper._swapDataDeserializer(resp.data.data);
741
+ if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED)
742
+ try {
743
+ await this._saveRealSwapData(data, save);
744
+ return true;
745
+ }
746
+ catch (e) { }
747
+ return null;
748
+ case IntermediaryAPI_1.InvoiceStatusResponseCodes.EXPIRED:
749
+ this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
750
+ this.initiated = true;
751
+ if (save)
752
+ await this._saveAndEmit();
753
+ return false;
754
+ default:
755
+ return null;
756
+ }
757
+ }
758
+ /**
759
+ * Checks and overrides the swap data for this swap. This is used to set the swap data from
760
+ * on-chain events.
761
+ *
762
+ * @param data Swap data of the escrow swap
763
+ * @param save If the new data should be saved
764
+ *
765
+ * @internal
766
+ */
767
+ async _saveRealSwapData(data, save) {
768
+ await this.checkIntermediaryReturnedData(data);
769
+ if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
770
+ this._state = FromBTCLNAutoSwapState.PR_PAID;
771
+ this._data = data;
772
+ this.initiated = true;
773
+ if (save)
774
+ await this._saveAndEmit();
775
+ return true;
776
+ }
777
+ return false;
778
+ }
779
+ /**
780
+ * Checks the data returned by the intermediary in the payment auth request
781
+ *
782
+ * @param data Parsed swap data as returned by the intermediary
783
+ *
784
+ * @throws {IntermediaryError} If the returned are not valid
785
+ * @throws {Error} If the swap is already committed on-chain
786
+ *
787
+ * @private
788
+ */
789
+ async checkIntermediaryReturnedData(data) {
790
+ if (!data.isPayOut())
791
+ throw new IntermediaryError_1.IntermediaryError("Invalid not pay out");
792
+ if (data.getType() !== base_1.ChainSwapType.HTLC)
793
+ throw new IntermediaryError_1.IntermediaryError("Invalid swap type");
794
+ if (!data.isOfferer(this.getSwapData().getOfferer()))
795
+ throw new IntermediaryError_1.IntermediaryError("Invalid offerer used");
796
+ if (!data.isClaimer(this._getInitiator()))
797
+ throw new IntermediaryError_1.IntermediaryError("Invalid claimer used");
798
+ if (!data.isToken(this.getSwapData().getToken()))
799
+ throw new IntermediaryError_1.IntermediaryError("Invalid token used");
800
+ if (data.getSecurityDeposit() !== this.getSwapData().getSecurityDeposit())
801
+ throw new IntermediaryError_1.IntermediaryError("Invalid security deposit!");
802
+ if (data.getClaimerBounty() !== this.getSwapData().getClaimerBounty())
803
+ throw new IntermediaryError_1.IntermediaryError("Invalid security deposit!");
804
+ if (data.getAmount() < this.getSwapData().getAmount())
805
+ throw new IntermediaryError_1.IntermediaryError("Invalid amount received!");
806
+ if (data.getClaimHash() !== this.getSwapData().getClaimHash())
807
+ throw new IntermediaryError_1.IntermediaryError("Invalid payment hash used!");
808
+ if (!data.isDepositToken(this.getSwapData().getDepositToken()))
809
+ throw new IntermediaryError_1.IntermediaryError("Invalid deposit token used!");
810
+ if (data.hasSuccessAction())
811
+ throw new IntermediaryError_1.IntermediaryError("Invalid has success action");
812
+ if (await this.wrapper._contract.isExpired(this._getInitiator(), data))
813
+ throw new IntermediaryError_1.IntermediaryError("Not enough time to claim!");
814
+ if (this.wrapper._getHtlcTimeout(data) <= (Date.now() / 1000))
815
+ throw new IntermediaryError_1.IntermediaryError("HTLC expires too soon!");
816
+ }
817
+ /**
818
+ * Waits till a lightning network payment is received by the intermediary, and the intermediary
819
+ * initiates the swap HTLC on the smart chain side. After the HTLC is initiated you can wait
820
+ * for an automatic settlement by the watchtowers with the {@link waitTillClaimed} function,
821
+ * or settle manually using the {@link claim} or {@link txsClaim} functions.
822
+ *
823
+ * If this swap is using an LNURL-withdraw link as input, it automatically posts the
824
+ * generated invoice to the LNURL service to pay it.
825
+ *
826
+ * @param onPaymentReceived Callback as for when the LP reports having received the ln payment
827
+ * @param abortSignal Abort signal to stop waiting for payment
828
+ * @param checkIntervalSeconds How often to poll the intermediary for answer (default 5 seconds)
829
+ */
830
+ async waitForPayment(onPaymentReceived, checkIntervalSeconds, abortSignal) {
831
+ checkIntervalSeconds ??= 5;
832
+ if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
833
+ await this.waitTillCommited(checkIntervalSeconds, abortSignal);
834
+ }
835
+ if (this._state >= FromBTCLNAutoSwapState.CLAIM_COMMITED)
836
+ return true;
837
+ if (this._state !== FromBTCLNAutoSwapState.PR_CREATED)
838
+ throw new Error("Must be in PR_CREATED state!");
839
+ const abortController = new AbortController();
840
+ if (abortSignal != null)
841
+ abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
842
+ let save = false;
843
+ if (this.lnurl != null && this.lnurlK1 != null && this.lnurlCallback != null && !this.prPosted) {
844
+ if (this.pr == null || !this.pr.toLowerCase().startsWith("ln"))
845
+ throw new Error("Input lightning network invoice not available, the swap was probably recovered!");
846
+ LNURL_1.LNURL.postInvoiceToLNURLWithdraw({ k1: this.lnurlK1, callback: this.lnurlCallback }, this.pr).catch(e => {
847
+ this.lnurlFailSignal.abort(e);
848
+ });
849
+ this.prPosted = true;
850
+ save ||= true;
851
+ }
852
+ if (!this.initiated) {
853
+ this.initiated = true;
854
+ save ||= true;
855
+ }
856
+ if (save)
857
+ await this._saveAndEmit();
858
+ let lnurlFailListener = () => abortController.abort(this.lnurlFailSignal.signal.reason);
859
+ this.lnurlFailSignal.signal.addEventListener("abort", lnurlFailListener);
860
+ this.lnurlFailSignal.signal.throwIfAborted();
861
+ const paymentHash = this.getPaymentHash();
862
+ if (paymentHash == null)
863
+ throw new Error("Swap payment hash not available, the swap was probably recovered!");
864
+ if (this.wrapper._messenger.warmup != null)
865
+ await this.wrapper._messenger.warmup().catch(e => {
866
+ this.logger.warn("waitForPayment(): Failed to warmup messenger: ", e);
867
+ });
868
+ if (this._state === FromBTCLNAutoSwapState.PR_CREATED) {
869
+ const promises = [
870
+ this.waitTillState(FromBTCLNAutoSwapState.PR_PAID, "gte", abortController.signal).then(() => true)
871
+ ];
872
+ if (this.url != null)
873
+ promises.push((async () => {
874
+ let resp = { code: IntermediaryAPI_1.InvoiceStatusResponseCodes.PENDING, msg: "" };
875
+ while (!abortController.signal.aborted && resp.code === IntermediaryAPI_1.InvoiceStatusResponseCodes.PENDING) {
876
+ resp = await IntermediaryAPI_1.IntermediaryAPI.getInvoiceStatus(this.url, paymentHash.toString("hex"));
877
+ if (resp.code === IntermediaryAPI_1.InvoiceStatusResponseCodes.PENDING)
878
+ await (0, TimeoutUtils_1.timeoutPromise)(checkIntervalSeconds * 1000, abortController.signal);
879
+ }
880
+ this.lnurlFailSignal.signal.removeEventListener("abort", lnurlFailListener);
881
+ abortController.signal.throwIfAborted();
882
+ if (resp.code === IntermediaryAPI_1.InvoiceStatusResponseCodes.PAID) {
883
+ const swapData = new this.wrapper._swapDataDeserializer(resp.data.data);
884
+ return await this._saveRealSwapData(swapData, true);
885
+ }
886
+ if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
887
+ if (resp.code === IntermediaryAPI_1.InvoiceStatusResponseCodes.EXPIRED) {
888
+ await this._saveAndEmit(FromBTCLNAutoSwapState.QUOTE_EXPIRED);
889
+ }
890
+ return false;
891
+ }
892
+ })());
893
+ const paymentResult = await Promise.race(promises);
894
+ abortController.abort();
895
+ if (!paymentResult)
896
+ return false;
897
+ if (onPaymentReceived != null)
898
+ onPaymentReceived(this.getInputTxId());
899
+ }
900
+ if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
901
+ await this.waitTillCommited(checkIntervalSeconds, abortSignal);
902
+ }
903
+ return this._state >= FromBTCLNAutoSwapState.CLAIM_COMMITED;
904
+ }
905
+ //////////////////////////////
906
+ //// Commit
907
+ /**
908
+ * Waits till the intermediary (LP) initiates the swap HTLC escrow on the destination smart chain side
909
+ *
910
+ * @param checkIntervalSeconds How often to check via a polling watchdog
911
+ * @param abortSignal Abort signal
912
+ *
913
+ * @internal
914
+ */
915
+ async waitTillCommited(checkIntervalSeconds, abortSignal) {
916
+ if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED || this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED)
917
+ return Promise.resolve();
918
+ if (this._state !== FromBTCLNAutoSwapState.PR_PAID)
919
+ throw new Error("Invalid state");
920
+ const abortController = (0, Utils_1.extendAbortController)(abortSignal);
921
+ let result;
922
+ try {
923
+ result = await Promise.race([
924
+ this.watchdogWaitTillCommited(checkIntervalSeconds, abortController.signal),
925
+ this.waitTillState(FromBTCLNAutoSwapState.CLAIM_COMMITED, "gte", abortController.signal).then(() => 0)
926
+ ]);
927
+ abortController.abort();
928
+ }
929
+ catch (e) {
930
+ abortController.abort();
931
+ throw e;
932
+ }
933
+ if (result === false) {
934
+ this.logger.debug("waitTillCommited(): Resolved from watchdog - HTLC expired");
935
+ if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
936
+ await this._saveAndEmit(FromBTCLNAutoSwapState.EXPIRED);
937
+ }
938
+ return;
939
+ }
940
+ if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
941
+ this._commitedAt ??= Date.now();
942
+ await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_COMMITED);
943
+ }
944
+ if (result === 0)
945
+ this.logger.debug("waitTillCommited(): Resolved from state changed");
946
+ if (result === true) {
947
+ this.logger.debug("waitTillCommited(): Resolved from watchdog - commited");
948
+ if (this.secret != null)
949
+ await this._broadcastSecret().catch(e => {
950
+ this.logger.error("waitTillCommited(): Error broadcasting swap secret: ", e);
951
+ });
952
+ }
953
+ }
954
+ //////////////////////////////
955
+ //// Claim
956
+ /**
957
+ * @inheritDoc
958
+ *
959
+ * @param _signer Optional signer address to use for claiming the swap, can also be different from the initializer
960
+ * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
961
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
962
+ *
963
+ * @throws {Error} If in invalid state (must be {@link FromBTCLNAutoSwapState.CLAIM_COMMITED})
964
+ */
965
+ async txsClaim(_signer, secret) {
966
+ let address = undefined;
967
+ if (_signer != null) {
968
+ if (typeof (_signer) === "string") {
969
+ address = _signer;
970
+ }
971
+ else if ((0, base_1.isAbstractSigner)(_signer)) {
972
+ address = _signer.getAddress();
973
+ }
974
+ else {
975
+ address = (await this.wrapper._chain.wrapSigner(_signer)).getAddress();
976
+ }
977
+ }
978
+ if (this._state !== FromBTCLNAutoSwapState.CLAIM_COMMITED)
979
+ throw new Error("Must be in CLAIM_COMMITED state!");
980
+ if (this._data == null)
981
+ throw new Error("Unknown data, wrong state?");
982
+ const useSecret = secret ?? this.secret;
983
+ if (useSecret == null)
984
+ throw new Error("Swap secret pre-image not known and not provided, please provide the swap secret pre-image as an argument");
985
+ if (!this.isValidSecretPreimage(useSecret))
986
+ throw new Error("Invalid swap secret pre-image provided!");
987
+ return await this.wrapper._contract.txsClaimWithSecret(address ?? this._getInitiator(), this._data, useSecret, true, true);
988
+ }
989
+ /**
990
+ * @inheritDoc
991
+ *
992
+ * @param _signer Signer to sign the transactions with, can also be different to the initializer
993
+ * @param abortSignal Abort signal to stop waiting for transaction confirmation
994
+ * @param onBeforeTxSent
995
+ * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
996
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
997
+ */
998
+ async claim(_signer, abortSignal, onBeforeTxSent, secret) {
999
+ const signer = (0, base_1.isAbstractSigner)(_signer) ? _signer : await this.wrapper._chain.wrapSigner(_signer);
1000
+ let txCount = 0;
1001
+ const txs = await this.txsClaim(_signer, secret);
1002
+ const result = await this.wrapper._chain.sendAndConfirm(signer, txs, true, abortSignal, undefined, (txId) => {
1003
+ txCount++;
1004
+ if (onBeforeTxSent != null && txCount === 1)
1005
+ onBeforeTxSent(txId);
1006
+ return Promise.resolve();
1007
+ });
1008
+ this._claimTxId = result[0];
1009
+ if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED || this._state === FromBTCLNAutoSwapState.EXPIRED || this._state === FromBTCLNAutoSwapState.FAILED) {
1010
+ await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_CLAIMED);
1011
+ }
1012
+ return result[0];
1013
+ }
1014
+ /**
1015
+ * Waits till the swap is successfully settled (claimed), should be called after sending the claim (settlement)
1016
+ * transactions manually to wait till the SDK processes the settlement and updates the swap state accordingly.
1017
+ *
1018
+ * @param maxWaitTimeSeconds Maximum time in seconds to wait for the swap to be settled
1019
+ * @param abortSignal AbortSignal
1020
+ * @param secret A swap secret to broadcast to watchtowers, generally only needed if the swap
1021
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
1022
+ *
1023
+ * @throws {Error} If swap is in invalid state (must be {@link FromBTCLNAutoSwapState.CLAIM_COMMITED})
1024
+ * @throws {Error} If the LP refunded sooner than we were able to claim
1025
+ * @returns {boolean} whether the swap was claimed in time or not
1026
+ */
1027
+ async waitTillClaimed(maxWaitTimeSeconds, abortSignal, secret) {
1028
+ if (this._state === FromBTCLNAutoSwapState.CLAIM_CLAIMED)
1029
+ return Promise.resolve(true);
1030
+ if (this._state !== FromBTCLNAutoSwapState.CLAIM_COMMITED)
1031
+ throw new Error("Invalid state (not CLAIM_COMMITED)");
1032
+ if (secret != null) {
1033
+ if (!this.isValidSecretPreimage(secret))
1034
+ throw new Error("Invalid swap secret pre-image provided!");
1035
+ this.secret = secret;
1036
+ }
1037
+ const abortController = new AbortController();
1038
+ if (abortSignal != null)
1039
+ abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
1040
+ let timedOut = false;
1041
+ if (maxWaitTimeSeconds != null) {
1042
+ const timeout = setTimeout(() => {
1043
+ timedOut = true;
1044
+ abortController.abort();
1045
+ }, maxWaitTimeSeconds * 1000);
1046
+ abortController.signal.addEventListener("abort", () => clearTimeout(timeout));
1047
+ }
1048
+ let res;
1049
+ try {
1050
+ res = await Promise.race([
1051
+ this.watchdogWaitTillResult(undefined, abortController.signal),
1052
+ this.waitTillState(FromBTCLNAutoSwapState.CLAIM_CLAIMED, "eq", abortController.signal).then(() => 0),
1053
+ this.waitTillState(FromBTCLNAutoSwapState.EXPIRED, "eq", abortController.signal).then(() => 1),
1054
+ ]);
1055
+ abortController.abort();
1056
+ }
1057
+ catch (e) {
1058
+ abortController.abort();
1059
+ if (timedOut)
1060
+ return false;
1061
+ throw e;
1062
+ }
1063
+ if (res === 0) {
1064
+ this.logger.debug("waitTillClaimed(): Resolved from state change (CLAIM_CLAIMED)");
1065
+ return true;
1066
+ }
1067
+ if (res === 1) {
1068
+ this.logger.debug("waitTillClaimed(): Resolved from state change (EXPIRED)");
1069
+ throw new Error("Swap expired during claiming");
1070
+ }
1071
+ this.logger.debug("waitTillClaimed(): Resolved from watchdog");
1072
+ if (res?.type === base_1.SwapCommitStateType.PAID) {
1073
+ if (this._state !== FromBTCLNAutoSwapState.CLAIM_CLAIMED) {
1074
+ this._claimTxId = await res.getClaimTxId();
1075
+ await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_CLAIMED);
1076
+ }
1077
+ }
1078
+ if (res?.type === base_1.SwapCommitStateType.NOT_COMMITED || res?.type === base_1.SwapCommitStateType.EXPIRED) {
1079
+ if (this._state !== FromBTCLNAutoSwapState.CLAIM_CLAIMED &&
1080
+ this._state !== FromBTCLNAutoSwapState.FAILED) {
1081
+ await this._saveAndEmit(FromBTCLNAutoSwapState.FAILED);
1082
+ }
1083
+ throw new Error("Swap expired during claiming");
1084
+ }
1085
+ return true;
1086
+ }
1087
+ //////////////////////////////
1088
+ //// LNURL
1089
+ /**
1090
+ * Whether this swap uses an LNURL-withdraw link
1091
+ */
1092
+ isLNURL() {
1093
+ return this.lnurl != null;
1094
+ }
1095
+ /**
1096
+ * Gets the used LNURL or `null` if this is not an LNURL-withdraw swap
1097
+ */
1098
+ getLNURL() {
1099
+ return this.lnurl ?? null;
1100
+ }
1101
+ /**
1102
+ * Pay the generated lightning network invoice with an LNURL-withdraw link, this
1103
+ * is useful when you want to display a lightning payment QR code and also want to
1104
+ * allow payments using LNURL-withdraw NFC cards.
1105
+ *
1106
+ * Note that the swap needs to be created **without** an LNURL to begin with for this function
1107
+ * to work. If this swap is already using an LNURL-withdraw link, this function throws.
1108
+ */
1109
+ async settleWithLNURLWithdraw(lnurl) {
1110
+ if (this._state !== FromBTCLNAutoSwapState.PR_CREATED &&
1111
+ this._state !== FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED)
1112
+ throw new Error("Must be in PR_CREATED state!");
1113
+ if (this.lnurl != null)
1114
+ throw new Error("Cannot settle LNURL-withdraw swap with different LNURL");
1115
+ let lnurlParams;
1116
+ if (typeof (lnurl) === "string") {
1117
+ const parsedLNURL = await LNURL_1.LNURL.getLNURL(lnurl);
1118
+ if (parsedLNURL == null || parsedLNURL.tag !== "withdrawRequest")
1119
+ throw new UserError_1.UserError("Invalid LNURL-withdraw to settle the swap");
1120
+ lnurlParams = parsedLNURL;
1121
+ }
1122
+ else {
1123
+ lnurlParams = lnurl.params;
1124
+ }
1125
+ if (this.pr == null || !this.pr.toLowerCase().startsWith("ln"))
1126
+ throw new Error("Input lightning network invoice not available, the swap was probably recovered!");
1127
+ LNURL_1.LNURL.useLNURLWithdraw(lnurlParams, this.pr).catch(e => this.lnurlFailSignal.abort(e));
1128
+ this.lnurl = lnurlParams.url;
1129
+ this.lnurlCallback = lnurlParams.callback;
1130
+ this.lnurlK1 = lnurlParams.k1;
1131
+ this.prPosted = true;
1132
+ await this._saveAndEmit();
1133
+ }
1134
+ //////////////////////////////
1135
+ //// Storage
1136
+ /**
1137
+ * @inheritDoc
1138
+ */
1139
+ serialize() {
1140
+ return {
1141
+ ...super.serialize(),
1142
+ data: this._data == null ? null : this._data.serialize(),
1143
+ commitTxId: this._commitTxId,
1144
+ claimTxId: this._claimTxId,
1145
+ commitedAt: this._commitedAt,
1146
+ btcAmountSwap: this.btcAmountSwap == null ? null : this.btcAmountSwap.toString(10),
1147
+ btcAmountGas: this.btcAmountGas == null ? null : this.btcAmountGas.toString(10),
1148
+ gasSwapFeeBtc: this.gasSwapFeeBtc == null ? null : this.gasSwapFeeBtc.toString(10),
1149
+ gasSwapFee: this.gasSwapFee == null ? null : this.gasSwapFee.toString(10),
1150
+ gasPricingInfo: (0, PriceInfoType_1.serializePriceInfoType)(this.gasPricingInfo),
1151
+ pr: this.pr,
1152
+ secret: this.secret,
1153
+ lnurl: this.lnurl,
1154
+ lnurlK1: this.lnurlK1,
1155
+ lnurlCallback: this.lnurlCallback,
1156
+ prPosted: this.prPosted,
1157
+ initialSwapData: this.initialSwapData.serialize(),
1158
+ usesClaimHashAsId: this.usesClaimHashAsId
1159
+ };
1160
+ }
1161
+ //////////////////////////////
1162
+ //// Swap ticks & sync
1163
+ /**
1164
+ * Checks the swap's state on-chain and compares it to its internal state, updates/changes it according to on-chain
1165
+ * data
1166
+ *
1167
+ * @private
1168
+ */
1169
+ async syncStateFromChain(quoteDefinitelyExpired, commitStatus) {
1170
+ if (this._state === FromBTCLNAutoSwapState.PR_PAID ||
1171
+ this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED ||
1172
+ this._state === FromBTCLNAutoSwapState.EXPIRED) {
1173
+ //Check for expiry before the getCommitStatus to prevent race conditions
1174
+ let quoteExpired = false;
1175
+ if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
1176
+ quoteExpired = quoteDefinitelyExpired ?? await this._verifyQuoteDefinitelyExpired();
1177
+ }
1178
+ //Check if it's already successfully paid
1179
+ commitStatus ??= await this.wrapper._contract.getCommitStatus(this._getInitiator(), this._data);
1180
+ if (commitStatus != null && await this._forciblySetOnchainState(commitStatus))
1181
+ return true;
1182
+ if (this._state === FromBTCLNAutoSwapState.PR_PAID) {
1183
+ if (quoteExpired) {
1184
+ this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1185
+ return true;
1186
+ }
1187
+ }
1188
+ }
1189
+ return false;
1190
+ }
1191
+ /**
1192
+ * @inheritDoc
1193
+ * @internal
1194
+ */
1195
+ _shouldFetchOnchainState() {
1196
+ return this._state === FromBTCLNAutoSwapState.PR_PAID || this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED || this._state === FromBTCLNAutoSwapState.EXPIRED;
1197
+ }
1198
+ /**
1199
+ * @inheritDoc
1200
+ * @internal
1201
+ */
1202
+ _shouldFetchExpiryStatus() {
1203
+ return this._state === FromBTCLNAutoSwapState.PR_PAID;
1204
+ }
1205
+ /**
1206
+ * @inheritDoc
1207
+ * @internal
1208
+ */
1209
+ _shouldCheckIntermediary() {
1210
+ return this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1211
+ }
1212
+ /**
1213
+ * @inheritDoc
1214
+ * @internal
1215
+ */
1216
+ async _sync(save, quoteDefinitelyExpired, commitStatus, skipLpCheck) {
1217
+ let changed = false;
1218
+ if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
1219
+ if (this._state !== FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED && this.getQuoteExpiry() < Date.now()) {
1220
+ this._state = FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1221
+ changed ||= true;
1222
+ }
1223
+ if (!skipLpCheck)
1224
+ try {
1225
+ const result = await this._checkIntermediaryPaymentReceived(false);
1226
+ if (result !== null)
1227
+ changed ||= true;
1228
+ }
1229
+ catch (e) {
1230
+ this.logger.error("_sync(): Failed to synchronize swap, error: ", e);
1231
+ }
1232
+ if (this._state === FromBTCLNAutoSwapState.PR_CREATED || this._state === FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
1233
+ if (await this._verifyQuoteDefinitelyExpired()) {
1234
+ this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1235
+ changed ||= true;
1236
+ }
1237
+ }
1238
+ }
1239
+ if (await this.syncStateFromChain(quoteDefinitelyExpired, commitStatus))
1240
+ changed = true;
1241
+ if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED) {
1242
+ const expired = await this.wrapper._contract.isExpired(this._getInitiator(), this._data);
1243
+ if (expired) {
1244
+ this._state = FromBTCLNAutoSwapState.EXPIRED;
1245
+ changed = true;
1246
+ }
1247
+ }
1248
+ if (save && changed)
1249
+ await this._saveAndEmit();
1250
+ if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED && this.secret != null)
1251
+ await this._broadcastSecret().catch(e => {
1252
+ this.logger.error("_sync(): Error when broadcasting swap secret: ", e);
1253
+ });
1254
+ return changed;
1255
+ }
1256
+ /**
1257
+ * @inheritDoc
1258
+ * @internal
1259
+ */
1260
+ async _forciblySetOnchainState(commitStatus) {
1261
+ switch (commitStatus?.type) {
1262
+ case base_1.SwapCommitStateType.PAID:
1263
+ if (this._claimTxId == null)
1264
+ this._claimTxId = await commitStatus.getClaimTxId();
1265
+ if (this.secret == null || this.pr == null)
1266
+ this._setSwapSecret(await commitStatus.getClaimResult());
1267
+ this._state = FromBTCLNAutoSwapState.CLAIM_CLAIMED;
1268
+ return true;
1269
+ case base_1.SwapCommitStateType.NOT_COMMITED:
1270
+ if (this._refundTxId == null && commitStatus.getRefundTxId != null)
1271
+ this._refundTxId = await commitStatus.getRefundTxId();
1272
+ if (this._refundTxId != null) {
1273
+ this._state = FromBTCLNAutoSwapState.FAILED;
1274
+ return true;
1275
+ }
1276
+ break;
1277
+ case base_1.SwapCommitStateType.EXPIRED:
1278
+ if (this._refundTxId == null && commitStatus.getRefundTxId != null)
1279
+ this._refundTxId = await commitStatus.getRefundTxId();
1280
+ this._state = this._refundTxId == null ? FromBTCLNAutoSwapState.QUOTE_EXPIRED : FromBTCLNAutoSwapState.FAILED;
1281
+ return true;
1282
+ case base_1.SwapCommitStateType.COMMITED:
1283
+ if (this._state !== FromBTCLNAutoSwapState.CLAIM_COMMITED && this._state !== FromBTCLNAutoSwapState.EXPIRED) {
1284
+ this._commitedAt ??= Date.now();
1285
+ this._state = FromBTCLNAutoSwapState.CLAIM_COMMITED;
1286
+ return true;
1287
+ }
1288
+ break;
1289
+ }
1290
+ return false;
1291
+ }
1292
+ /**
1293
+ * Broadcasts the swap secret to the underlying data propagation layer (e.g. Nostr by default)
1294
+ *
1295
+ * @param noCheckExpiry Whether a swap expiration check should be skipped broadcasting
1296
+ * @param secret An optional secret pre-image for the swap to broadcast
1297
+ *
1298
+ * @internal
1299
+ */
1300
+ async _broadcastSecret(noCheckExpiry, secret) {
1301
+ if (this._state !== FromBTCLNAutoSwapState.CLAIM_COMMITED)
1302
+ throw new Error("Must be in CLAIM_COMMITED state to broadcast swap secret!");
1303
+ if (this._data == null)
1304
+ throw new Error("Unknown data, wrong state?");
1305
+ const useSecret = secret ?? this.secret;
1306
+ if (useSecret == null)
1307
+ throw new Error("Swap secret pre-image not known and not provided, please provide the swap secret pre-image as an argument");
1308
+ if (!this.isValidSecretPreimage(useSecret))
1309
+ throw new Error("Invalid swap secret pre-image provided!");
1310
+ if (!noCheckExpiry) {
1311
+ if (await this.wrapper._contract.isExpired(this._getInitiator(), this._data))
1312
+ throw new Error("On-chain HTLC already expired!");
1313
+ }
1314
+ await this.wrapper._messenger.broadcast(new base_1.SwapClaimWitnessMessage(this._data, useSecret));
1315
+ }
1316
+ /**
1317
+ * @inheritDoc
1318
+ * @internal
1319
+ */
1320
+ async _tick(save) {
1321
+ switch (this._state) {
1322
+ case FromBTCLNAutoSwapState.PR_CREATED:
1323
+ if (this.getQuoteExpiry() < Date.now()) {
1324
+ this._state = FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1325
+ if (save)
1326
+ await this._saveAndEmit();
1327
+ return true;
1328
+ }
1329
+ break;
1330
+ case FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED:
1331
+ if (this.getDefinitiveExpiryTime() < Date.now()) {
1332
+ this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1333
+ if (save)
1334
+ await this._saveAndEmit();
1335
+ return true;
1336
+ }
1337
+ break;
1338
+ case FromBTCLNAutoSwapState.PR_PAID:
1339
+ case FromBTCLNAutoSwapState.CLAIM_COMMITED:
1340
+ const expired = await this.wrapper._contract.isExpired(this._getInitiator(), this._data);
1341
+ if (expired) {
1342
+ this._state = FromBTCLNAutoSwapState.EXPIRED;
1343
+ if (save)
1344
+ await this._saveAndEmit();
1345
+ return true;
1346
+ }
1347
+ if (this._state === FromBTCLNAutoSwapState.CLAIM_COMMITED) {
1348
+ //Broadcast the secret over the provided messenger channel
1349
+ if (this.broadcastTickCounter === 0 && this.secret != null)
1350
+ await this._broadcastSecret(true).catch(e => {
1351
+ this.logger.warn("_tick(): Error when broadcasting swap secret: ", e);
1352
+ });
1353
+ this.broadcastTickCounter = (this.broadcastTickCounter + 1) % 3; //Broadcast every 3rd tick
1354
+ }
1355
+ break;
1356
+ }
1357
+ return false;
1358
+ }
1359
+ /**
1360
+ * Forcibly sets the swap secret pre-image from on-chain data
1361
+ *
1362
+ * @internal
1363
+ */
1364
+ _setSwapSecret(secret) {
1365
+ this.secret = secret;
1366
+ if (this.pr == null) {
1367
+ this.pr = buffer_1.Buffer.from((0, sha2_1.sha256)(buffer_1.Buffer.from(secret, "hex"))).toString("hex");
1368
+ }
1369
+ }
1370
+ }
1371
+ exports.FromBTCLNAutoSwap = FromBTCLNAutoSwap;