@atomiqlabs/sdk 8.1.8 → 8.3.5

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 (261) hide show
  1. package/dist/bitcoin/coinselect2/utils.d.ts +6 -0
  2. package/dist/bitcoin/wallet/BitcoinWallet.d.ts +41 -5
  3. package/dist/bitcoin/wallet/BitcoinWallet.js +36 -1
  4. package/dist/bitcoin/wallet/IBitcoinWallet.d.ts +52 -2
  5. package/dist/bitcoin/wallet/IBitcoinWallet.js +2 -1
  6. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.d.ts +42 -7
  7. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.js +36 -1
  8. package/dist/enums/FeeType.d.ts +8 -1
  9. package/dist/enums/FeeType.js +8 -1
  10. package/dist/enums/SwapAmountType.d.ts +7 -0
  11. package/dist/enums/SwapAmountType.js +7 -0
  12. package/dist/enums/SwapDirection.d.ts +7 -0
  13. package/dist/enums/SwapDirection.js +7 -0
  14. package/dist/enums/SwapType.d.ts +62 -1
  15. package/dist/enums/SwapType.js +62 -1
  16. package/dist/errors/IntermediaryError.d.ts +4 -0
  17. package/dist/errors/IntermediaryError.js +1 -0
  18. package/dist/errors/RequestError.d.ts +15 -1
  19. package/dist/errors/RequestError.js +8 -0
  20. package/dist/errors/UserError.d.ts +1 -0
  21. package/dist/errors/UserError.js +1 -0
  22. package/dist/index.d.ts +5 -5
  23. package/dist/index.js +7 -6
  24. package/dist/intermediaries/Intermediary.d.ts +61 -14
  25. package/dist/intermediaries/Intermediary.js +38 -11
  26. package/dist/intermediaries/IntermediaryDiscovery.d.ts +62 -29
  27. package/dist/intermediaries/IntermediaryDiscovery.js +39 -24
  28. package/dist/prices/RedundantSwapPrice.d.ts +26 -5
  29. package/dist/prices/RedundantSwapPrice.js +22 -2
  30. package/dist/prices/SingleSwapPrice.d.ts +10 -7
  31. package/dist/prices/SingleSwapPrice.js +11 -8
  32. package/dist/prices/SwapPriceWithChain.d.ts +56 -19
  33. package/dist/prices/SwapPriceWithChain.js +62 -25
  34. package/dist/prices/abstract/IPriceProvider.d.ts +4 -4
  35. package/dist/prices/abstract/IPriceProvider.js +1 -1
  36. package/dist/prices/abstract/ISwapPrice.d.ts +95 -46
  37. package/dist/prices/abstract/ISwapPrice.js +104 -56
  38. package/dist/prices/providers/BinancePriceProvider.d.ts +8 -1
  39. package/dist/prices/providers/BinancePriceProvider.js +8 -1
  40. package/dist/prices/providers/CoinGeckoPriceProvider.d.ts +7 -1
  41. package/dist/prices/providers/CoinGeckoPriceProvider.js +7 -1
  42. package/dist/prices/providers/CoinPaprikaPriceProvider.d.ts +7 -1
  43. package/dist/prices/providers/CoinPaprikaPriceProvider.js +7 -1
  44. package/dist/prices/providers/CustomPriceProvider.d.ts +12 -1
  45. package/dist/prices/providers/CustomPriceProvider.js +12 -1
  46. package/dist/prices/providers/KrakenPriceProvider.d.ts +10 -1
  47. package/dist/prices/providers/KrakenPriceProvider.js +10 -1
  48. package/dist/prices/providers/OKXPriceProvider.d.ts +7 -1
  49. package/dist/prices/providers/OKXPriceProvider.js +7 -1
  50. package/dist/prices/providers/abstract/ExchangePriceProvider.d.ts +3 -0
  51. package/dist/prices/providers/abstract/ExchangePriceProvider.js +3 -0
  52. package/dist/storage/IUnifiedStorage.d.ts +19 -7
  53. package/dist/storage/UnifiedSwapStorage.d.ts +33 -3
  54. package/dist/storage/UnifiedSwapStorage.js +29 -1
  55. package/dist/storage-browser/IndexedDBUnifiedStorage.d.ts +31 -7
  56. package/dist/storage-browser/IndexedDBUnifiedStorage.js +29 -6
  57. package/dist/storage-browser/LocalStorageManager.d.ts +25 -1
  58. package/dist/storage-browser/LocalStorageManager.js +25 -1
  59. package/dist/swapper/Swapper.d.ts +380 -226
  60. package/dist/swapper/Swapper.js +383 -349
  61. package/dist/swapper/SwapperFactory.d.ts +66 -18
  62. package/dist/swapper/SwapperFactory.js +24 -3
  63. package/dist/swapper/SwapperUtils.d.ts +75 -28
  64. package/dist/swapper/SwapperUtils.js +107 -60
  65. package/dist/swapper/SwapperWithChain.d.ts +286 -91
  66. package/dist/swapper/SwapperWithChain.js +218 -64
  67. package/dist/swapper/SwapperWithSigner.d.ts +229 -80
  68. package/dist/swapper/SwapperWithSigner.js +190 -44
  69. package/dist/swaps/IAddressSwap.d.ts +12 -3
  70. package/dist/swaps/IAddressSwap.js +3 -2
  71. package/dist/swaps/IBTCWalletSwap.d.ts +26 -8
  72. package/dist/swaps/IBTCWalletSwap.js +3 -2
  73. package/dist/swaps/IClaimableSwap.d.ts +38 -6
  74. package/dist/swaps/IClaimableSwap.js +3 -2
  75. package/dist/swaps/IClaimableSwapWrapper.d.ts +11 -1
  76. package/dist/swaps/IRefundableSwap.d.ts +31 -5
  77. package/dist/swaps/IRefundableSwap.js +3 -2
  78. package/dist/swaps/ISwap.d.ts +162 -24
  79. package/dist/swaps/ISwap.js +92 -35
  80. package/dist/swaps/ISwapWithGasDrop.d.ts +8 -2
  81. package/dist/swaps/ISwapWithGasDrop.js +2 -1
  82. package/dist/swaps/ISwapWrapper.d.ts +161 -52
  83. package/dist/swaps/ISwapWrapper.js +131 -73
  84. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.d.ts +51 -6
  85. package/dist/swaps/escrow_swaps/IEscrowSelfInitSwap.js +22 -12
  86. package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +65 -12
  87. package/dist/swaps/escrow_swaps/IEscrowSwap.js +38 -19
  88. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +39 -9
  89. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +30 -21
  90. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +31 -15
  91. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +33 -18
  92. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.d.ts +97 -28
  93. package/dist/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.js +91 -27
  94. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.d.ts +22 -9
  95. package/dist/swaps/escrow_swaps/frombtc/IFromBTCWrapper.js +24 -11
  96. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +278 -60
  97. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +519 -241
  98. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +77 -26
  99. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +132 -50
  100. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +313 -52
  101. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +544 -194
  102. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +87 -26
  103. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +147 -58
  104. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +222 -55
  105. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +462 -244
  106. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +77 -23
  107. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +116 -46
  108. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +195 -58
  109. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +324 -191
  110. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.d.ts +30 -5
  111. package/dist/swaps/escrow_swaps/tobtc/IToBTCWrapper.js +44 -19
  112. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.d.ts +61 -20
  113. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.js +75 -32
  114. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +76 -50
  115. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +106 -101
  116. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.d.ts +37 -14
  117. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.js +66 -20
  118. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +46 -17
  119. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +82 -27
  120. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +350 -88
  121. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +482 -215
  122. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +76 -24
  123. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +247 -124
  124. package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +148 -20
  125. package/dist/swaps/trusted/ln/LnForGasSwap.js +175 -45
  126. package/dist/swaps/trusted/ln/LnForGasWrapper.d.ts +29 -10
  127. package/dist/swaps/trusted/ln/LnForGasWrapper.js +30 -11
  128. package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +202 -49
  129. package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +232 -80
  130. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.d.ts +34 -12
  131. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +33 -14
  132. package/dist/types/AmountData.d.ts +2 -1
  133. package/dist/types/CustomPriceFunction.d.ts +8 -2
  134. package/dist/types/PriceInfoType.d.ts +4 -4
  135. package/dist/types/PriceInfoType.js +3 -3
  136. package/dist/types/SwapExecutionAction.d.ts +85 -4
  137. package/dist/types/SwapWithSigner.d.ts +5 -2
  138. package/dist/types/SwapWithSigner.js +5 -2
  139. package/dist/types/Token.d.ts +11 -5
  140. package/dist/types/Token.js +6 -3
  141. package/dist/types/TokenAmount.d.ts +3 -0
  142. package/dist/types/TokenAmount.js +2 -0
  143. package/dist/types/fees/Fee.d.ts +3 -2
  144. package/dist/types/fees/FeeBreakdown.d.ts +3 -2
  145. package/dist/types/fees/PercentagePPM.d.ts +4 -2
  146. package/dist/types/fees/PercentagePPM.js +2 -1
  147. package/dist/types/lnurl/LNURLPay.d.ts +20 -12
  148. package/dist/types/lnurl/LNURLPay.js +8 -4
  149. package/dist/types/lnurl/LNURLWithdraw.d.ts +17 -10
  150. package/dist/types/lnurl/LNURLWithdraw.js +8 -4
  151. package/dist/types/wallets/LightningInvoiceCreateService.d.ts +24 -0
  152. package/dist/types/wallets/LightningInvoiceCreateService.js +15 -0
  153. package/dist/types/wallets/MinimalBitcoinWalletInterface.d.ts +3 -1
  154. package/dist/types/wallets/MinimalLightningNetworkWalletInterface.d.ts +4 -2
  155. package/dist/utils/BitcoinUtils.d.ts +1 -0
  156. package/dist/utils/BitcoinUtils.js +5 -1
  157. package/dist/utils/SwapUtils.d.ts +58 -1
  158. package/dist/utils/SwapUtils.js +55 -1
  159. package/dist/utils/TokenUtils.d.ts +10 -2
  160. package/dist/utils/TokenUtils.js +12 -4
  161. package/package.json +3 -3
  162. package/src/bitcoin/coinselect2/utils.ts +6 -0
  163. package/src/bitcoin/wallet/BitcoinWallet.ts +41 -5
  164. package/src/bitcoin/wallet/IBitcoinWallet.ts +57 -2
  165. package/src/bitcoin/wallet/SingleAddressBitcoinWallet.ts +42 -6
  166. package/src/enums/FeeType.ts +8 -1
  167. package/src/enums/SwapAmountType.ts +7 -0
  168. package/src/enums/SwapDirection.ts +7 -0
  169. package/src/enums/SwapType.ts +62 -2
  170. package/src/errors/IntermediaryError.ts +4 -0
  171. package/src/errors/RequestError.ts +15 -1
  172. package/src/errors/UserError.ts +1 -0
  173. package/src/index.ts +12 -5
  174. package/src/intermediaries/Intermediary.ts +61 -14
  175. package/src/intermediaries/IntermediaryDiscovery.ts +69 -34
  176. package/src/prices/RedundantSwapPrice.ts +26 -6
  177. package/src/prices/SingleSwapPrice.ts +11 -8
  178. package/src/prices/SwapPriceWithChain.ts +63 -26
  179. package/src/prices/abstract/IPriceProvider.ts +4 -4
  180. package/src/prices/abstract/ISwapPrice.ts +115 -66
  181. package/src/prices/providers/BinancePriceProvider.ts +8 -1
  182. package/src/prices/providers/CoinGeckoPriceProvider.ts +7 -1
  183. package/src/prices/providers/CoinPaprikaPriceProvider.ts +7 -1
  184. package/src/prices/providers/CustomPriceProvider.ts +12 -1
  185. package/src/prices/providers/KrakenPriceProvider.ts +10 -1
  186. package/src/prices/providers/OKXPriceProvider.ts +7 -1
  187. package/src/prices/providers/abstract/ExchangePriceProvider.ts +3 -0
  188. package/src/storage/IUnifiedStorage.ts +19 -7
  189. package/src/storage/UnifiedSwapStorage.ts +33 -3
  190. package/src/storage-browser/IndexedDBUnifiedStorage.ts +31 -8
  191. package/src/storage-browser/LocalStorageManager.ts +25 -1
  192. package/src/swapper/Swapper.ts +599 -390
  193. package/src/swapper/SwapperFactory.ts +73 -24
  194. package/src/swapper/SwapperUtils.ts +107 -60
  195. package/src/swapper/SwapperWithChain.ts +320 -81
  196. package/src/swapper/SwapperWithSigner.ts +263 -56
  197. package/src/swaps/IAddressSwap.ts +13 -3
  198. package/src/swaps/IBTCWalletSwap.ts +26 -10
  199. package/src/swaps/IClaimableSwap.ts +41 -6
  200. package/src/swaps/IClaimableSwapWrapper.ts +11 -2
  201. package/src/swaps/IRefundableSwap.ts +34 -5
  202. package/src/swaps/ISwap.ts +224 -85
  203. package/src/swaps/ISwapWithGasDrop.ts +8 -2
  204. package/src/swaps/ISwapWrapper.ts +216 -98
  205. package/src/swaps/escrow_swaps/IEscrowSelfInitSwap.ts +64 -18
  206. package/src/swaps/escrow_swaps/IEscrowSwap.ts +83 -37
  207. package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +61 -30
  208. package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +37 -19
  209. package/src/swaps/escrow_swaps/frombtc/IFromBTCSelfInitSwap.ts +123 -50
  210. package/src/swaps/escrow_swaps/frombtc/IFromBTCWrapper.ts +24 -11
  211. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +562 -258
  212. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +156 -62
  213. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +592 -227
  214. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +177 -74
  215. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +483 -245
  216. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +141 -59
  217. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +350 -195
  218. package/src/swaps/escrow_swaps/tobtc/IToBTCWrapper.ts +48 -23
  219. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNSwap.ts +87 -40
  220. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +110 -110
  221. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCSwap.ts +89 -34
  222. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +101 -31
  223. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +556 -259
  224. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +292 -148
  225. package/src/swaps/trusted/ln/LnForGasSwap.ts +186 -47
  226. package/src/swaps/trusted/ln/LnForGasWrapper.ts +34 -15
  227. package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +262 -88
  228. package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +41 -19
  229. package/src/types/AmountData.ts +2 -1
  230. package/src/types/CustomPriceFunction.ts +8 -2
  231. package/src/types/PriceInfoType.ts +4 -4
  232. package/src/types/SwapExecutionAction.ts +97 -5
  233. package/src/types/SwapWithSigner.ts +8 -4
  234. package/src/types/Token.ts +12 -5
  235. package/src/types/TokenAmount.ts +3 -0
  236. package/src/types/fees/Fee.ts +3 -2
  237. package/src/types/fees/FeeBreakdown.ts +3 -2
  238. package/src/types/fees/PercentagePPM.ts +4 -2
  239. package/src/types/lnurl/LNURLPay.ts +20 -12
  240. package/src/types/lnurl/LNURLWithdraw.ts +17 -10
  241. package/src/types/wallets/LightningInvoiceCreateService.ts +30 -0
  242. package/src/types/wallets/MinimalBitcoinWalletInterface.ts +3 -1
  243. package/src/types/wallets/MinimalLightningNetworkWalletInterface.ts +4 -2
  244. package/src/utils/BitcoinUtils.ts +5 -0
  245. package/src/utils/SwapUtils.ts +63 -1
  246. package/src/utils/TokenUtils.ts +12 -4
  247. package/dist/bitcoin/BitcoinRpcWithAddressIndex.d.ts +0 -68
  248. package/dist/bitcoin/BitcoinRpcWithAddressIndex.js +0 -2
  249. package/dist/bitcoin/LightningNetworkApi.d.ts +0 -12
  250. package/dist/bitcoin/LightningNetworkApi.js +0 -2
  251. package/dist/bitcoin/mempool/MempoolApi.d.ts +0 -350
  252. package/dist/bitcoin/mempool/MempoolApi.js +0 -311
  253. package/dist/bitcoin/mempool/MempoolBitcoinBlock.d.ts +0 -44
  254. package/dist/bitcoin/mempool/MempoolBitcoinBlock.js +0 -48
  255. package/dist/bitcoin/mempool/MempoolBitcoinRpc.d.ts +0 -119
  256. package/dist/bitcoin/mempool/MempoolBitcoinRpc.js +0 -361
  257. package/dist/bitcoin/mempool/synchronizer/MempoolBtcRelaySynchronizer.d.ts +0 -22
  258. package/dist/bitcoin/mempool/synchronizer/MempoolBtcRelaySynchronizer.js +0 -105
  259. package/dist/errors/PaymentAuthError.d.ts +0 -11
  260. package/dist/errors/PaymentAuthError.js +0 -23
  261. package/src/errors/PaymentAuthError.ts +0 -26
@@ -6,10 +6,10 @@ import {
6
6
  ChainSwapType,
7
7
  ChainType, isAbstractSigner,
8
8
  SignatureData,
9
- SignatureVerificationError,
10
9
  SwapCommitState,
11
10
  SwapCommitStateType,
12
- SwapData
11
+ SwapData,
12
+ SignatureVerificationError
13
13
  } from "@atomiqlabs/base";
14
14
  import {Buffer} from "buffer";
15
15
  import {LNURL} from "../../../../lnurl/LNURL";
@@ -30,25 +30,59 @@ import {BitcoinTokens, BtcToken, SCToken} from "../../../../types/Token";
30
30
  import {getLogger, LoggerType} from "../../../../utils/Logger";
31
31
  import {timeoutPromise} from "../../../../utils/TimeoutUtils";
32
32
  import {isLNURLWithdraw, LNURLWithdraw, LNURLWithdrawParamsWithUrl} from "../../../../types/lnurl/LNURLWithdraw";
33
+ import {sha256} from "@noble/hashes/sha2";
33
34
 
34
35
  /**
35
- * State enum for FromBTCLN swaps
36
- * @category Swaps
36
+ * State enum for legacy Lightning -> Smart chain swaps
37
+ * @category Swaps/Legacy/Lightning → Smart chain
37
38
  */
38
39
  export enum FromBTCLNSwapState {
40
+ /**
41
+ * Swap has failed as the user didn't settle the HTLC on the destination before expiration
42
+ */
39
43
  FAILED = -4,
44
+ /**
45
+ * Swap has expired for good and there is no way how it can be executed anymore
46
+ */
40
47
  QUOTE_EXPIRED = -3,
48
+ /**
49
+ * A swap is almost expired, and it should be presented to the user as expired, though
50
+ * there is still a chance that it will be processed
51
+ */
41
52
  QUOTE_SOFT_EXPIRED = -2,
53
+ /**
54
+ * Swap HTLC on the destination chain has expired, it is not safe anymore to settle (claim) the
55
+ * swap on the destination smart chain.
56
+ */
42
57
  EXPIRED = -1,
58
+ /**
59
+ * Swap quote was created, use {@link FromBTCLNSwap.getAddress} or {@link FromBTCLNSwap.getHyperlink}
60
+ * to get the bolt11 lightning network invoice to pay to initiate the swap, then use the
61
+ * {@link FromBTCLNSwap.waitForPayment} to wait till the lightning network payment is received
62
+ * by the intermediary (LP)
63
+ */
43
64
  PR_CREATED = 0,
65
+ /**
66
+ * Lightning network payment has been received by the intermediary (LP), the user can now settle
67
+ * the swap on the destination smart chain side with {@link FromBTCLNSwap.commitAndClaim} (if
68
+ * the underlying chain supports it - check with {@link FromBTCLNSwap.canCommitAndClaimInOneShot}),
69
+ * or by calling {@link FromBTCLNSwap.commit} and {@link FromBTCLNSwap.claim} separately.
70
+ */
44
71
  PR_PAID = 1,
72
+ /**
73
+ * Swap escrow HTLC has been created on the destination chain. Continue by claiming it with the
74
+ * {@link FromBTCLNSwap.claim} or {@link FromBTCLNSwap.txsClaim} function.
75
+ */
45
76
  CLAIM_COMMITED = 2,
77
+ /**
78
+ * Swap successfully settled and funds received on the destination chain
79
+ */
46
80
  CLAIM_CLAIMED = 3
47
81
  }
48
82
 
49
83
  export type FromBTCLNSwapInit<T extends SwapData> = IEscrowSelfInitSwapInit<T> & {
50
- pr: string,
51
- secret: string,
84
+ pr?: string,
85
+ secret?: string,
52
86
  initialSwapData: T,
53
87
  lnurl?: string,
54
88
  lnurlK1?: string,
@@ -56,35 +90,61 @@ export type FromBTCLNSwapInit<T extends SwapData> = IEscrowSelfInitSwapInit<T> &
56
90
  };
57
91
 
58
92
  export function isFromBTCLNSwapInit<T extends SwapData>(obj: any): obj is FromBTCLNSwapInit<T> {
59
- return typeof obj.pr==="string" &&
60
- typeof obj.secret==="string" &&
93
+ return (obj.pr==null || typeof obj.pr==="string") &&
94
+ (obj.secret==null || typeof obj.secret==="string") &&
61
95
  (obj.lnurl==null || typeof(obj.lnurl)==="string") &&
62
96
  (obj.lnurlK1==null || typeof(obj.lnurlK1)==="string") &&
63
97
  (obj.lnurlCallback==null || typeof(obj.lnurlCallback)==="string") &&
64
98
  isIEscrowSelfInitSwapInit(obj);
65
99
  }
66
100
 
101
+ /**
102
+ * Legacy escrow (HTLC) based swap for Bitcoin Lightning -> Smart chains, requires manual settlement
103
+ * of the swap on the destination network once the lightning network payment is received by the LP.
104
+ *
105
+ * @category Swaps/Legacy/Lightning → Smart chain
106
+ */
67
107
  export class FromBTCLNSwap<T extends ChainType = ChainType>
68
108
  extends IFromBTCSelfInitSwap<T, FromBTCLNDefinition<T>, FromBTCLNSwapState>
69
109
  implements IAddressSwap, IClaimableSwap<T, FromBTCLNDefinition<T>, FromBTCLNSwapState> {
70
110
 
111
+ protected readonly TYPE = SwapType.FROM_BTCLN;
112
+ /**
113
+ * @internal
114
+ */
71
115
  protected readonly logger: LoggerType;
116
+ /**
117
+ * @internal
118
+ */
72
119
  protected readonly inputToken: BtcToken<true> = BitcoinTokens.BTCLN;
73
- protected readonly TYPE = SwapType.FROM_BTCLN;
74
120
 
75
- protected readonly lnurlFailSignal: AbortController = new AbortController();
121
+ private readonly lnurlFailSignal: AbortController = new AbortController();
122
+ private readonly usesClaimHashAsId: boolean;
123
+ private readonly initialSwapData: T["Data"];
76
124
 
77
- protected readonly pr: string;
78
- protected readonly secret: string;
79
- protected initialSwapData: T["Data"];
125
+ /**
126
+ * In case the swap is recovered from on-chain data, the pr saved here is just a payment hash,
127
+ * as it is impossible to retrieve the actual lightning network invoice paid purely from on-chain
128
+ * data
129
+ * @private
130
+ */
131
+ private pr?: string;
132
+ private secret?: string;
80
133
 
81
- lnurl?: string;
82
- lnurlK1?: string;
83
- lnurlCallback?: string;
84
- prPosted?: boolean = false;
134
+ private lnurl?: string;
135
+ private lnurlK1?: string;
136
+ private lnurlCallback?: string;
137
+ private prPosted?: boolean = false;
85
138
 
86
- protected getSwapData(): T["Data"] {
87
- return this.data ?? this.initialSwapData;
139
+ /**
140
+ * Sets the LNURL data for the swap
141
+ *
142
+ * @internal
143
+ */
144
+ _setLNURLData(lnurl: string, lnurlK1: string, lnurlCallback: string) {
145
+ this.lnurl = lnurl;
146
+ this.lnurlK1 = lnurlK1;
147
+ this.lnurlCallback = lnurlCallback;
88
148
  }
89
149
 
90
150
  constructor(wrapper: FromBTCLNWrapper<T>, init: FromBTCLNSwapInit<T["Data"]>);
@@ -96,19 +156,20 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
96
156
  if(isFromBTCLNSwapInit(initOrObject) && initOrObject.url!=null) initOrObject.url += "/frombtcln";
97
157
  super(wrapper, initOrObject);
98
158
  if(isFromBTCLNSwapInit(initOrObject)) {
99
- this.state = FromBTCLNSwapState.PR_CREATED;
159
+ this._state = FromBTCLNSwapState.PR_CREATED;
100
160
  this.pr = initOrObject.pr;
101
161
  this.secret = initOrObject.secret;
102
162
  this.initialSwapData = initOrObject.initialSwapData;
103
163
  this.lnurl = initOrObject.lnurl;
104
164
  this.lnurlK1 = initOrObject.lnurlK1;
105
165
  this.lnurlCallback = initOrObject.lnurlCallback;
166
+ this.usesClaimHashAsId = true;
106
167
  } else {
107
168
  this.pr = initOrObject.pr;
108
169
  this.secret = initOrObject.secret;
109
170
 
110
171
  if(initOrObject.initialSwapData==null) {
111
- this.initialSwapData = this.data!;
172
+ this.initialSwapData = this._data!;
112
173
  } else {
113
174
  this.initialSwapData = SwapData.deserialize<T["Data"]>(initOrObject.initialSwapData);
114
175
  }
@@ -118,35 +179,48 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
118
179
  this.lnurlCallback = initOrObject.lnurlCallback;
119
180
  this.prPosted = initOrObject.prPosted;
120
181
 
121
- if(this.state===FromBTCLNSwapState.PR_CREATED && this.data!=null) {
122
- this.initialSwapData = this.data;
123
- delete this.data;
182
+ if(this._state===FromBTCLNSwapState.PR_CREATED && this._data!=null) {
183
+ this.initialSwapData = this._data;
184
+ delete this._data;
124
185
  }
186
+ this.usesClaimHashAsId = initOrObject.usesClaimHashAsId ?? false;
125
187
  }
126
188
  this.tryRecomputeSwapPrice();
127
189
  this.logger = getLogger("FromBTCLN("+this.getIdentifierHashString()+"): ");
128
190
  }
129
191
 
192
+ /**
193
+ * @inheritDoc
194
+ * @internal
195
+ */
196
+ protected getSwapData(): T["Data"] {
197
+ return this._data ?? this.initialSwapData;
198
+ }
199
+
200
+ /**
201
+ * @inheritDoc
202
+ * @internal
203
+ */
130
204
  protected upgradeVersion() {
131
205
  if (this.version == null) {
132
- switch (this.state) {
206
+ switch (this._state) {
133
207
  case -2:
134
- this.state = FromBTCLNSwapState.QUOTE_EXPIRED;
208
+ this._state = FromBTCLNSwapState.QUOTE_EXPIRED;
135
209
  break;
136
210
  case -1:
137
- this.state = FromBTCLNSwapState.FAILED;
211
+ this._state = FromBTCLNSwapState.FAILED;
138
212
  break;
139
213
  case 0:
140
- this.state = FromBTCLNSwapState.PR_CREATED
214
+ this._state = FromBTCLNSwapState.PR_CREATED
141
215
  break;
142
216
  case 1:
143
- this.state = FromBTCLNSwapState.PR_PAID
217
+ this._state = FromBTCLNSwapState.PR_PAID
144
218
  break;
145
219
  case 2:
146
- this.state = FromBTCLNSwapState.CLAIM_COMMITED
220
+ this._state = FromBTCLNSwapState.CLAIM_COMMITED
147
221
  break;
148
222
  case 3:
149
- this.state = FromBTCLNSwapState.CLAIM_CLAIMED
223
+ this._state = FromBTCLNSwapState.CLAIM_CLAIMED
150
224
  break;
151
225
  }
152
226
  this.version = 1;
@@ -156,39 +230,80 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
156
230
  //////////////////////////////
157
231
  //// Getters & utils
158
232
 
233
+ /**
234
+ * @inheritDoc
235
+ * @internal
236
+ */
159
237
  protected getIdentifierHash(): Buffer {
160
- const paymentHashBuffer = this.getPaymentHash();
161
- if(this.randomNonce==null) return paymentHashBuffer;
162
- return Buffer.concat([paymentHashBuffer, Buffer.from(this.randomNonce, "hex")]);
238
+ const idBuffer: Buffer = this.usesClaimHashAsId
239
+ ? Buffer.from(this.getClaimHash(), "hex")
240
+ : this.getPaymentHash()!;
241
+ if(this._randomNonce==null) return idBuffer;
242
+ return Buffer.concat([idBuffer, Buffer.from(this._randomNonce, "hex")]);
163
243
  }
164
244
 
165
- protected getPaymentHash(): Buffer {
166
- const decodedPR = bolt11Decode(this.pr);
167
- if(decodedPR.tagsObject.payment_hash==null) throw new Error("Swap invoice doesn't contain payment hash field!");
168
- return Buffer.from(decodedPR.tagsObject.payment_hash, "hex");
245
+ /**
246
+ * Returns the payment hash of the swap and lightning network invoice, or `null` if not known (i.e. if
247
+ * the swap was recovered from on-chain data, the payment hash might not be known)
248
+ *
249
+ * @internal
250
+ */
251
+ protected getPaymentHash(): Buffer | null {
252
+ if(this.pr==null) return null;
253
+ if(this.pr.toLowerCase().startsWith("ln")) {
254
+ const parsed = bolt11Decode(this.pr);
255
+ if(parsed.tagsObject.payment_hash==null) throw new Error("Swap invoice has no payment hash field!");
256
+ return Buffer.from(parsed.tagsObject.payment_hash, "hex");
257
+ }
258
+ return Buffer.from(this.pr, "hex");
169
259
  }
170
260
 
261
+ /**
262
+ * @inheritDoc
263
+ * @internal
264
+ */
171
265
  protected canCommit(): boolean {
172
- return this.state===FromBTCLNSwapState.PR_PAID;
266
+ return this._state===FromBTCLNSwapState.PR_PAID;
173
267
  }
174
268
 
269
+ /**
270
+ * @inheritDoc
271
+ */
175
272
  getInputAddress(): string | null {
176
- return this.lnurl ?? this.pr;
273
+ return this.lnurl ?? this.pr ?? null;
177
274
  }
178
275
 
179
- getInputTxId(): string {
180
- return this.getPaymentHash().toString("hex");
276
+ /**
277
+ * @inheritDoc
278
+ */
279
+ getInputTxId(): string | null {
280
+ const paymentHash = this.getPaymentHash();
281
+ if(paymentHash==null) return null;
282
+ return paymentHash.toString("hex");
181
283
  }
182
284
 
183
285
  /**
184
- * Returns the lightning network BOLT11 invoice that needs to be paid as an input to the swap
286
+ * Returns the lightning network BOLT11 invoice that needs to be paid as an input to the swap.
287
+ *
288
+ * In case the swap is recovered from on-chain data, the address returned might be just a payment hash,
289
+ * as it is impossible to retrieve the actual lightning network invoice paid purely from on-chain
290
+ * data.
185
291
  */
186
292
  getAddress(): string {
187
- return this.pr;
293
+ return this.pr ?? "";
188
294
  }
189
295
 
296
+ /**
297
+ * A hyperlink representation of the address + amount that the user needs to sends on the source chain.
298
+ * This is suitable to be displayed in a form of QR code.
299
+ *
300
+ * @remarks
301
+ * In case the swap is recovered from on-chain data, the address returned might be just a payment hash,
302
+ * as it is impossible to retrieve the actual lightning network invoice paid purely from on-chain
303
+ * data.
304
+ */
190
305
  getHyperlink(): string {
191
- return "lightning:"+this.pr.toUpperCase();
306
+ return this.pr==null ? "" : "lightning:"+this.pr.toUpperCase();
192
307
  }
193
308
 
194
309
  /**
@@ -196,114 +311,163 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
196
311
  * if the LP doesn't make it expired sooner
197
312
  */
198
313
  getDefinitiveExpiryTime(): number {
314
+ if(this.pr==null || !this.pr.toLowerCase().startsWith("ln")) return 0;
199
315
  const decoded = bolt11Decode(this.pr);
200
316
  if(decoded.timeExpireDate==null) throw new Error("Swap invoice doesn't contain expiry date field!");
201
317
  const finalCltvExpiryDelta = decoded.tagsObject.min_final_cltv_expiry ?? 144;
202
- const finalCltvExpiryDelay = finalCltvExpiryDelta * this.wrapper.options.bitcoinBlocktime * this.wrapper.options.safetyFactor;
318
+ const finalCltvExpiryDelay = finalCltvExpiryDelta * this.wrapper._options.bitcoinBlocktime * this.wrapper._options.safetyFactor;
203
319
  return (decoded.timeExpireDate + finalCltvExpiryDelay)*1000;
204
320
  }
205
321
 
322
+ /**
323
+ * Returns timeout time (in UNIX milliseconds) when the swap htlc will expire
324
+ */
325
+ getHtlcTimeoutTime(): number | null {
326
+ if(this._data==null) return null;
327
+ return Number(this.wrapper._getHtlcTimeout(this._data))*1000;
328
+ }
329
+
206
330
  /**
207
331
  * Returns timeout time (in UNIX milliseconds) when the LN invoice will expire
208
332
  */
209
333
  getTimeoutTime(): number {
334
+ if(this.pr==null || !this.pr.toLowerCase().startsWith("ln")) return 0;
210
335
  const decoded = bolt11Decode(this.pr);
211
336
  if(decoded.timeExpireDate==null) throw new Error("Swap invoice doesn't contain expiry date field!");
212
337
  return (decoded.timeExpireDate*1000);
213
338
  }
214
339
 
215
340
  /**
216
- * Returns timeout time (in UNIX milliseconds) when the swap htlc will expire
341
+ * @inheritDoc
217
342
  */
218
- getHtlcTimeoutTime(): number {
219
- if(this.data==null) return -1;
220
- return Number(this.wrapper.getHtlcTimeout(this.data))*1000;
221
- }
222
-
223
343
  isFinished(): boolean {
224
- return this.state===FromBTCLNSwapState.CLAIM_CLAIMED || this.state===FromBTCLNSwapState.QUOTE_EXPIRED || this.state===FromBTCLNSwapState.FAILED;
344
+ return this._state===FromBTCLNSwapState.CLAIM_CLAIMED || this._state===FromBTCLNSwapState.QUOTE_EXPIRED || this._state===FromBTCLNSwapState.FAILED;
225
345
  }
226
346
 
347
+ /**
348
+ * @inheritDoc
349
+ */
227
350
  isClaimable(): boolean {
228
- return this.state===FromBTCLNSwapState.CLAIM_COMMITED;
351
+ return this._state===FromBTCLNSwapState.CLAIM_COMMITED;
229
352
  }
230
353
 
354
+ /**
355
+ * @inheritDoc
356
+ */
231
357
  isSuccessful(): boolean {
232
- return this.state===FromBTCLNSwapState.CLAIM_CLAIMED;
358
+ return this._state===FromBTCLNSwapState.CLAIM_CLAIMED;
233
359
  }
234
360
 
361
+ /**
362
+ * @inheritDoc
363
+ */
235
364
  isFailed(): boolean {
236
- return this.state===FromBTCLNSwapState.FAILED || this.state===FromBTCLNSwapState.EXPIRED;
365
+ return this._state===FromBTCLNSwapState.FAILED || this._state===FromBTCLNSwapState.EXPIRED;
237
366
  }
238
367
 
368
+ /**
369
+ * @inheritDoc
370
+ */
239
371
  isQuoteExpired(): boolean {
240
- return this.state===FromBTCLNSwapState.QUOTE_EXPIRED;
372
+ return this._state===FromBTCLNSwapState.QUOTE_EXPIRED;
241
373
  }
242
374
 
375
+ /**
376
+ * @inheritDoc
377
+ */
243
378
  isQuoteSoftExpired(): boolean {
244
- return this.state===FromBTCLNSwapState.QUOTE_EXPIRED || this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED;
379
+ return this._state===FromBTCLNSwapState.QUOTE_EXPIRED || this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED;
245
380
  }
246
381
 
382
+ /**
383
+ * @inheritDoc
384
+ * @internal
385
+ */
247
386
  _verifyQuoteDefinitelyExpired(): Promise<boolean> {
248
- if(this.state===FromBTCLNSwapState.PR_CREATED || (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData==null)) {
387
+ if(this._state===FromBTCLNSwapState.PR_CREATED || (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData==null)) {
249
388
  return Promise.resolve(this.getDefinitiveExpiryTime()<Date.now());
250
389
  }
251
390
  return super._verifyQuoteDefinitelyExpired();
252
391
  }
253
392
 
254
- verifyQuoteValid(): Promise<boolean> {
393
+ /**
394
+ * @inheritDoc
395
+ * @internal
396
+ */
397
+ _verifyQuoteValid(): Promise<boolean> {
255
398
  if(
256
- this.state===FromBTCLNSwapState.PR_CREATED ||
257
- (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData==null)
399
+ this._state===FromBTCLNSwapState.PR_CREATED ||
400
+ (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData==null)
258
401
  ) {
259
402
  return Promise.resolve(this.getTimeoutTime()>Date.now());
260
403
  }
261
- return super.verifyQuoteValid();
404
+ return super._verifyQuoteValid();
262
405
  }
263
406
 
264
407
 
265
408
  //////////////////////////////
266
409
  //// Amounts & fees
267
410
 
411
+ /**
412
+ * @inheritDoc
413
+ */
268
414
  getInputToken(): BtcToken<true> {
269
415
  return BitcoinTokens.BTCLN;
270
416
  }
271
417
 
418
+ /**
419
+ * @inheritDoc
420
+ */
272
421
  getInput(): TokenAmount<T["ChainId"], BtcToken<true>> {
422
+ if(this.pr==null || !this.pr.toLowerCase().startsWith("ln"))
423
+ return toTokenAmount(null, this.inputToken, this.wrapper._prices, this.pricingInfo);
424
+
273
425
  const parsed = bolt11Decode(this.pr);
274
426
  if(parsed.millisatoshis==null) throw new Error("Swap invoice doesn't contain msat amount field!");
275
427
  const amount = (BigInt(parsed.millisatoshis) + 999n) / 1000n;
276
- return toTokenAmount(amount, this.inputToken, this.wrapper.prices, this.pricingInfo);
428
+ return toTokenAmount(amount, this.inputToken, this.wrapper._prices, this.pricingInfo);
277
429
  }
278
430
 
279
- async getSmartChainNetworkFee(): Promise<TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>> {
280
- return toTokenAmount(await this.getCommitAndClaimFee(), this.wrapper.getNativeToken(), this.wrapper.prices, this.pricingInfo);
431
+ /**
432
+ * @inheritDoc
433
+ */
434
+ getSmartChainNetworkFee(): Promise<TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>> {
435
+ return this.getCommitAndClaimNetworkFee();
281
436
  }
282
437
 
438
+ /**
439
+ * @inheritDoc
440
+ */
283
441
  async hasEnoughForTxFees(): Promise<{
284
442
  enoughBalance: boolean,
285
443
  balance: TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>,
286
444
  required: TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>
287
445
  }> {
288
446
  const [balance, feeRate] = await Promise.all([
289
- this.wrapper.contract.getBalance(this._getInitiator(), this.wrapper.chain.getNativeCurrencyAddress(), false),
290
- this.feeRate!=null ? Promise.resolve<string>(this.feeRate) : this.wrapper.contract.getInitFeeRate(
447
+ this.wrapper._contract.getBalance(this._getInitiator(), this.wrapper._chain.getNativeCurrencyAddress(), false),
448
+ this.feeRate!=null ? Promise.resolve<string>(this.feeRate) : this.wrapper._contract.getInitFeeRate(
291
449
  this.getSwapData().getOfferer(),
292
450
  this.getSwapData().getClaimer(),
293
451
  this.getSwapData().getToken(),
294
452
  this.getSwapData().getClaimHash()
295
453
  )
296
454
  ]);
297
- const commitFee = await this.wrapper.contract.getCommitFee(this._getInitiator(), this.getSwapData(), feeRate);
298
- const claimFee = await this.wrapper.contract.getClaimFee(this._getInitiator(), this.getSwapData(), feeRate);
455
+ const commitFee = await this.wrapper._contract.getCommitFee(this._getInitiator(), this.getSwapData(), feeRate);
456
+ const claimFee = await this.wrapper._contract.getClaimFee(this._getInitiator(), this.getSwapData(), feeRate);
299
457
  const totalFee = commitFee + claimFee + this.getSwapData().getTotalDeposit();
300
458
  return {
301
459
  enoughBalance: balance >= totalFee,
302
- balance: toTokenAmount(balance, this.wrapper.getNativeToken(), this.wrapper.prices, this.pricingInfo),
303
- required: toTokenAmount(totalFee, this.wrapper.getNativeToken(), this.wrapper.prices, this.pricingInfo)
460
+ balance: toTokenAmount(balance, this.wrapper._getNativeToken(), this.wrapper._prices, this.pricingInfo),
461
+ required: toTokenAmount(totalFee, this.wrapper._getNativeToken(), this.wrapper._prices, this.pricingInfo)
304
462
  };
305
463
  }
306
464
 
465
+ private isValidSecretPreimage(secret: string) {
466
+ const paymentHash = Buffer.from(sha256(Buffer.from(secret, "hex")));
467
+ const claimHash = this.wrapper._contract.getHashForHtlc(paymentHash).toString("hex");
468
+ return this.getSwapData().getClaimHash()===claimHash;
469
+ }
470
+
307
471
 
308
472
  //////////////////////////////
309
473
  //// Execution
@@ -318,6 +482,8 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
318
482
  * link, wallet is not required and the LN invoice can be paid externally as well (just pass null or undefined here)
319
483
  * @param callbacks Callbacks to track the progress of the swap
320
484
  * @param options Optional options for the swap like feeRate, AbortSignal, and timeouts/intervals
485
+ * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
486
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
321
487
  */
322
488
  async execute(
323
489
  dstSigner: T["Signer"] | T["NativeSigner"],
@@ -332,17 +498,21 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
332
498
  abortSignal?: AbortSignal,
333
499
  lightningTxCheckIntervalSeconds?: number,
334
500
  delayBetweenCommitAndClaimSeconds?: number
335
- }
501
+ },
502
+ secret?: string
336
503
  ): Promise<void> {
337
- if(this.state===FromBTCLNSwapState.FAILED) throw new Error("Swap failed!");
338
- if(this.state===FromBTCLNSwapState.EXPIRED) throw new Error("Swap HTLC expired!");
339
- if(this.state===FromBTCLNSwapState.QUOTE_EXPIRED || this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED) throw new Error("Swap quote expired!");
340
- if(this.state===FromBTCLNSwapState.CLAIM_CLAIMED) throw new Error("Swap already settled!");
504
+ if(this._state===FromBTCLNSwapState.FAILED) throw new Error("Swap failed!");
505
+ if(this._state===FromBTCLNSwapState.EXPIRED) throw new Error("Swap HTLC expired!");
506
+ if(this._state===FromBTCLNSwapState.QUOTE_EXPIRED || this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED) throw new Error("Swap quote expired!");
507
+ if(this._state===FromBTCLNSwapState.CLAIM_CLAIMED) throw new Error("Swap already settled!");
341
508
 
342
509
  let abortSignal = options?.abortSignal;
343
510
 
344
- if(this.state===FromBTCLNSwapState.PR_CREATED) {
511
+ if(this._state===FromBTCLNSwapState.PR_CREATED) {
345
512
  if(walletOrLnurlWithdraw!=null && this.lnurl==null) {
513
+ if(this.pr==null || !this.pr.toLowerCase().startsWith("ln"))
514
+ throw new Error("Input lightning network invoice not available, the swap was probably recovered!");
515
+
346
516
  if(typeof(walletOrLnurlWithdraw)==="string" || isLNURLWithdraw(walletOrLnurlWithdraw)) {
347
517
  await this.settleWithLNURLWithdraw(walletOrLnurlWithdraw);
348
518
  } else {
@@ -358,39 +528,48 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
358
528
  if (!paymentSuccess) throw new Error("Failed to receive lightning network payment");
359
529
  }
360
530
 
361
- if(this.state===FromBTCLNSwapState.PR_PAID || this.state===FromBTCLNSwapState.CLAIM_COMMITED) {
531
+ if(this._state===FromBTCLNSwapState.PR_PAID || this._state===FromBTCLNSwapState.CLAIM_COMMITED) {
362
532
  if(this.canCommitAndClaimInOneShot()) {
363
- await this.commitAndClaim(dstSigner, options?.abortSignal, undefined, callbacks?.onDestinationCommitSent, callbacks?.onDestinationClaimSent);
533
+ await this.commitAndClaim(dstSigner, options?.abortSignal, undefined, callbacks?.onDestinationCommitSent, callbacks?.onDestinationClaimSent, secret);
364
534
  } else {
365
- if(this.state===FromBTCLNSwapState.PR_PAID) {
535
+ if(this._state===FromBTCLNSwapState.PR_PAID) {
366
536
  await this.commit(dstSigner, options?.abortSignal, undefined, callbacks?.onDestinationCommitSent);
367
537
  if(options?.delayBetweenCommitAndClaimSeconds!=null) await timeoutPromise(options.delayBetweenCommitAndClaimSeconds * 1000, options?.abortSignal);
368
538
  }
369
- if(this.state===FromBTCLNSwapState.CLAIM_COMMITED) {
370
- await this.claim(dstSigner, options?.abortSignal, callbacks?.onDestinationClaimSent);
539
+ if(this._state===FromBTCLNSwapState.CLAIM_COMMITED) {
540
+ await this.claim(dstSigner, options?.abortSignal, callbacks?.onDestinationClaimSent, secret);
371
541
  }
372
542
  }
373
543
  }
374
544
 
375
545
  // @ts-ignore
376
- if(this.state===FromBTCLNSwapState.CLAIM_CLAIMED) {
546
+ if(this._state===FromBTCLNSwapState.CLAIM_CLAIMED) {
377
547
  if(callbacks?.onSwapSettled!=null) callbacks.onSwapSettled(this.getOutputTxId()!);
378
548
  }
379
549
  }
380
550
 
381
- async txsExecute(options?: {
382
- skipChecks?: boolean
383
- }) {
384
- if(this.state===FromBTCLNSwapState.PR_CREATED) {
385
- if(!await this.verifyQuoteValid()) throw new Error("Quote already expired or close to expiry!");
551
+ /**
552
+ * @inheritDoc
553
+ *
554
+ * @param options
555
+ * @param options.skipChecks Skip checks like making sure init signature is still valid and swap
556
+ * wasn't commited yet (this is handled on swap creation, if you commit right after quoting, you
557
+ * can use `skipChecks=true`)
558
+ * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
559
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
560
+ */
561
+ async txsExecute(options?: { skipChecks?: boolean }, secret?: string) {
562
+ if(this._state===FromBTCLNSwapState.PR_CREATED) {
563
+ if(!await this._verifyQuoteValid()) throw new Error("Quote already expired or close to expiry!");
386
564
  return [
387
565
  {
388
566
  name: "Payment" as const,
389
567
  description: "Initiates the swap by paying up the lightning network invoice",
390
- chain: "LIGHTNING",
568
+ chain: "LIGHTNING" as const,
391
569
  txs: [
392
570
  {
393
- address: this.pr,
571
+ type: "BOLT11_PAYMENT_REQUEST" as const,
572
+ address: this.getAddress(),
394
573
  hyperlink: this.getHyperlink()
395
574
  }
396
575
  ]
@@ -398,10 +577,10 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
398
577
  ];
399
578
  }
400
579
 
401
- if(this.state===FromBTCLNSwapState.PR_PAID) {
402
- if(!await this.verifyQuoteValid()) throw new Error("Quote already expired or close to expiry!");
580
+ if(this._state===FromBTCLNSwapState.PR_PAID) {
581
+ if(!await this._verifyQuoteValid()) throw new Error("Quote already expired or close to expiry!");
403
582
  const txsCommit = await this.txsCommit(options?.skipChecks);
404
- const txsClaim = await this._txsClaim(undefined);
583
+ const txsClaim = await this._txsClaim(undefined, secret);
405
584
  return [
406
585
  {
407
586
  name: "Commit" as const,
@@ -418,8 +597,8 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
418
597
  ];
419
598
  }
420
599
 
421
- if(this.state===FromBTCLNSwapState.CLAIM_COMMITED) {
422
- const txsClaim = await this.txsClaim();
600
+ if(this._state===FromBTCLNSwapState.CLAIM_COMMITED) {
601
+ const txsClaim = await this.txsClaim(undefined, secret);
423
602
  return [
424
603
  {
425
604
  name: "Claim" as const,
@@ -441,28 +620,36 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
441
620
  * Checks whether the LP received the LN payment and we can continue by committing & claiming the HTLC on-chain
442
621
  *
443
622
  * @param save If the new swap state should be saved
623
+ *
624
+ * @internal
444
625
  */
445
626
  async _checkIntermediaryPaymentReceived(save: boolean = true): Promise<boolean | null> {
446
627
  if(
447
- this.state===FromBTCLNSwapState.PR_PAID ||
448
- this.state===FromBTCLNSwapState.CLAIM_COMMITED ||
449
- this.state===FromBTCLNSwapState.CLAIM_CLAIMED ||
450
- this.state===FromBTCLNSwapState.FAILED
628
+ this._state===FromBTCLNSwapState.PR_PAID ||
629
+ this._state===FromBTCLNSwapState.CLAIM_COMMITED ||
630
+ this._state===FromBTCLNSwapState.CLAIM_CLAIMED ||
631
+ this._state===FromBTCLNSwapState.FAILED ||
632
+ this._state===FromBTCLNSwapState.EXPIRED
451
633
  ) return true;
452
- if(this.state===FromBTCLNSwapState.QUOTE_EXPIRED || (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null)) return false;
634
+ if(this._state===FromBTCLNSwapState.QUOTE_EXPIRED || (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null)) return false;
453
635
  if(this.url==null) return false;
454
- const resp = await IntermediaryAPI.getPaymentAuthorization(this.url, this.getPaymentHash().toString("hex"));
636
+
637
+ const paymentHash = this.getPaymentHash();
638
+ if(paymentHash==null)
639
+ throw new Error("Failed to check LP payment received, payment hash not known (probably recovered swap?)");
640
+
641
+ const resp = await IntermediaryAPI.getPaymentAuthorization(this.url, paymentHash.toString("hex"));
455
642
  switch(resp.code) {
456
643
  case PaymentAuthorizationResponseCodes.AUTH_DATA:
457
- const data = new this.wrapper.swapDataDeserializer(resp.data.data);
644
+ const data = new this.wrapper._swapDataDeserializer(resp.data.data);
458
645
  try {
459
646
  await this.checkIntermediaryReturnedAuthData(this._getInitiator(), data, resp.data);
460
- this.expiry = await this.wrapper.contract.getInitAuthorizationExpiry(
647
+ this.expiry = await this.wrapper._contract.getInitAuthorizationExpiry(
461
648
  data,
462
649
  resp.data
463
650
  );
464
- this.state = FromBTCLNSwapState.PR_PAID;
465
- this.data = data;
651
+ this._state = FromBTCLNSwapState.PR_PAID;
652
+ this._data = data;
466
653
  this.signatureData = {
467
654
  prefix: resp.data.prefix,
468
655
  timeout: resp.data.timeout,
@@ -474,7 +661,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
474
661
  } catch (e) {}
475
662
  return null;
476
663
  case PaymentAuthorizationResponseCodes.EXPIRED:
477
- this.state = FromBTCLNSwapState.QUOTE_EXPIRED;
664
+ this._state = FromBTCLNSwapState.QUOTE_EXPIRED;
478
665
  this.initiated = true;
479
666
  if(save) await this._saveAndEmit();
480
667
  return false;
@@ -489,10 +676,12 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
489
676
  * @param signer Smart chain signer's address initiating the swap
490
677
  * @param data Parsed swap data as returned by the intermediary
491
678
  * @param signature Signature data as returned by the intermediary
492
- * @protected
679
+ *
493
680
  * @throws {IntermediaryError} If the returned are not valid
494
681
  * @throws {SignatureVerificationError} If the returned signature is not valid
495
682
  * @throws {Error} If the swap is already committed on-chain
683
+ *
684
+ * @internal
496
685
  */
497
686
  protected async checkIntermediaryReturnedAuthData(signer: string, data: T["Data"], signature: SignatureData): Promise<void> {
498
687
  data.setClaimer(signer);
@@ -509,8 +698,8 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
509
698
  if (data.hasSuccessAction()) throw new IntermediaryError("Invalid has success action");
510
699
 
511
700
  await Promise.all([
512
- this.wrapper.contract.isValidInitAuthorization(this._getInitiator(), data, signature, this.feeRate),
513
- this.wrapper.contract.getCommitStatus(data.getClaimer(), data)
701
+ this.wrapper._contract.isValidInitAuthorization(this._getInitiator(), data, signature, this.feeRate),
702
+ this.wrapper._contract.getCommitStatus(data.getClaimer(), data)
514
703
  .then(status => {
515
704
  if (status?.type !== SwapCommitStateType.NOT_COMMITED)
516
705
  throw new Error("Swap already committed on-chain!");
@@ -519,17 +708,24 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
519
708
  }
520
709
 
521
710
  /**
522
- * Waits till an LN payment is received by the intermediary and client can continue commiting & claiming the HTLC
711
+ * Waits till a lightning network payment is received by the intermediary and client
712
+ * can continue by initiating (committing) & settling (claiming) the HTLC by calling
713
+ * either the {@link commitAndClaim} function (if the underlying chain allows commit
714
+ * and claim in a single transaction - check with {@link canCommitAndClaimInOneShot}).
715
+ * Or call {@link commit} and then {@link claim} separately.
716
+ *
717
+ * If this swap is using an LNURL-withdraw link as input, it automatically posts the
718
+ * generated invoice to the LNURL service to pay it.
523
719
  *
524
720
  * @param onPaymentReceived Callback as for when the LP reports having received the ln payment
525
721
  * @param abortSignal Abort signal to stop waiting for payment
526
- * @param checkIntervalSeconds How often to poll the intermediary for answer
722
+ * @param checkIntervalSeconds How often to poll the intermediary for answer (default 5 seconds)
527
723
  */
528
724
  async waitForPayment(onPaymentReceived?: (txId: string) => void, checkIntervalSeconds?: number, abortSignal?: AbortSignal): Promise<boolean> {
529
725
  checkIntervalSeconds ??= 5;
530
726
  if(
531
- this.state!==FromBTCLNSwapState.PR_CREATED &&
532
- (this.state!==FromBTCLNSwapState.QUOTE_SOFT_EXPIRED || this.signatureData!=null)
727
+ this._state!==FromBTCLNSwapState.PR_CREATED &&
728
+ (this._state!==FromBTCLNSwapState.QUOTE_SOFT_EXPIRED || this.signatureData!=null)
533
729
  ) throw new Error("Must be in PR_CREATED state!");
534
730
  if(this.url==null) throw new Error("LP URL not known, cannot await the payment!");
535
731
 
@@ -539,6 +735,9 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
539
735
  let save = false;
540
736
 
541
737
  if(this.lnurl!=null && this.lnurlK1!=null && this.lnurlCallback!=null && !this.prPosted) {
738
+ if(this.pr==null || !this.pr.toLowerCase().startsWith("ln"))
739
+ throw new Error("Input lightning network invoice not available, the swap was probably recovered!");
740
+
542
741
  LNURL.postInvoiceToLNURLWithdraw({k1: this.lnurlK1, callback: this.lnurlCallback}, this.pr).catch(e => {
543
742
  this.lnurlFailSignal.abort(e);
544
743
  });
@@ -557,9 +756,13 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
557
756
  this.lnurlFailSignal.signal.addEventListener("abort", lnurlFailListener);
558
757
  this.lnurlFailSignal.signal.throwIfAborted();
559
758
 
759
+ const paymentHash = this.getPaymentHash();
760
+ if(paymentHash==null)
761
+ throw new Error("Swap payment hash not available, the swap was probably recovered!");
762
+
560
763
  let resp: PaymentAuthorizationResponse = {code: PaymentAuthorizationResponseCodes.PENDING, msg: ""};
561
764
  while(!abortController.signal.aborted && resp.code===PaymentAuthorizationResponseCodes.PENDING) {
562
- resp = await IntermediaryAPI.getPaymentAuthorization(this.url, this.getPaymentHash().toString("hex"));
765
+ resp = await IntermediaryAPI.getPaymentAuthorization(this.url, paymentHash.toString("hex"));
563
766
  if(resp.code===PaymentAuthorizationResponseCodes.PENDING)
564
767
  await timeoutPromise(checkIntervalSeconds*1000, abortController.signal);
565
768
  }
@@ -568,15 +771,15 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
568
771
 
569
772
  if(resp.code===PaymentAuthorizationResponseCodes.AUTH_DATA) {
570
773
  const sigData = resp.data;
571
- const swapData = new this.wrapper.swapDataDeserializer(resp.data.data);
774
+ const swapData = new this.wrapper._swapDataDeserializer(resp.data.data);
572
775
  await this.checkIntermediaryReturnedAuthData(this._getInitiator(), swapData, sigData);
573
- this.expiry = await this.wrapper.contract.getInitAuthorizationExpiry(
776
+ this.expiry = await this.wrapper._contract.getInitAuthorizationExpiry(
574
777
  swapData,
575
778
  sigData
576
779
  );
577
- if(onPaymentReceived!=null) onPaymentReceived(this.getInputTxId());
578
- if(this.state===FromBTCLNSwapState.PR_CREATED || this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED) {
579
- this.data = swapData;
780
+ if(onPaymentReceived!=null) onPaymentReceived(this.getInputTxId()!);
781
+ if(this._state===FromBTCLNSwapState.PR_CREATED || this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED) {
782
+ this._data = swapData;
580
783
  this.signatureData = {
581
784
  prefix: sigData.prefix,
582
785
  timeout: sigData.timeout,
@@ -587,7 +790,7 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
587
790
  return true;
588
791
  }
589
792
 
590
- if(this.state===FromBTCLNSwapState.PR_CREATED || this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED) {
793
+ if(this._state===FromBTCLNSwapState.PR_CREATED || this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED) {
591
794
  if(resp.code===PaymentAuthorizationResponseCodes.EXPIRED) {
592
795
  await this._saveAndEmit(FromBTCLNSwapState.QUOTE_EXPIRED);
593
796
  }
@@ -603,21 +806,16 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
603
806
  //// Commit
604
807
 
605
808
  /**
606
- * Commits the swap on-chain, locking the tokens from the intermediary in an HTLC
809
+ * @inheritDoc
607
810
  *
608
- * @param _signer Signer to sign the transactions with, must be the same as used in the initialization
609
- * @param abortSignal Abort signal to stop waiting for the transaction confirmation and abort
610
- * @param skipChecks Skip checks like making sure init signature is still valid and swap wasn't commited yet
611
- * (this is handled when swap is created (quoted), if you commit right after quoting, you can use skipChecks=true)
612
- * @param onBeforeTxSent
613
811
  * @throws {Error} If invalid signer is provided that doesn't match the swap data
614
812
  */
615
813
  async commit(_signer: T["Signer"] | T["NativeSigner"], abortSignal?: AbortSignal, skipChecks?: boolean, onBeforeTxSent?: (txId: string) => void): Promise<string> {
616
- const signer = isAbstractSigner(_signer) ? _signer : await this.wrapper.chain.wrapSigner(_signer);
814
+ const signer = isAbstractSigner(_signer) ? _signer : await this.wrapper._chain.wrapSigner(_signer);
617
815
  this.checkSigner(signer);
618
816
  let txCount = 0;
619
817
  const txs = await this.txsCommit(skipChecks);
620
- const result = await this.wrapper.chain.sendAndConfirm(
818
+ const result = await this.wrapper._chain.sendAndConfirm(
621
819
  signer, txs, true, abortSignal, undefined, (txId: string) => {
622
820
  txCount++;
623
821
  if(onBeforeTxSent!=null && txCount===txs.length) onBeforeTxSent(txId);
@@ -625,16 +823,19 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
625
823
  }
626
824
  );
627
825
 
628
- this.commitTxId = result[result.length-1];
629
- if(this.state===FromBTCLNSwapState.PR_PAID || this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED) {
826
+ this._commitTxId = result[result.length-1];
827
+ if(this._state===FromBTCLNSwapState.PR_PAID || this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED) {
630
828
  await this._saveAndEmit(FromBTCLNSwapState.CLAIM_COMMITED);
631
829
  }
632
- return this.commitTxId;
830
+ return this._commitTxId;
633
831
  }
634
832
 
833
+ /**
834
+ * @inheritDoc
835
+ */
635
836
  async waitTillCommited(abortSignal?: AbortSignal): Promise<void> {
636
- if(this.state===FromBTCLNSwapState.CLAIM_COMMITED || this.state===FromBTCLNSwapState.CLAIM_CLAIMED) return Promise.resolve();
637
- if(this.state!==FromBTCLNSwapState.PR_PAID && (this.state!==FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null)) throw new Error("Invalid state");
837
+ if(this._state===FromBTCLNSwapState.CLAIM_COMMITED || this._state===FromBTCLNSwapState.CLAIM_CLAIMED) return Promise.resolve();
838
+ if(this._state!==FromBTCLNSwapState.PR_PAID && (this._state!==FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null)) throw new Error("Invalid state");
638
839
 
639
840
  const abortController = extendAbortController(abortSignal);
640
841
  const result = await Promise.race([
@@ -648,8 +849,8 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
648
849
  if(result===false) {
649
850
  this.logger.debug("waitTillCommited(): Resolved from watchdog - signature expired");
650
851
  if(
651
- this.state===FromBTCLNSwapState.PR_PAID ||
652
- this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED
852
+ this._state===FromBTCLNSwapState.PR_PAID ||
853
+ this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED
653
854
  ) {
654
855
  await this._saveAndEmit(FromBTCLNSwapState.QUOTE_EXPIRED);
655
856
  }
@@ -657,8 +858,8 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
657
858
  }
658
859
 
659
860
  if(
660
- this.state===FromBTCLNSwapState.PR_PAID ||
661
- this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED
861
+ this._state===FromBTCLNSwapState.PR_PAID ||
862
+ this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED
662
863
  ) {
663
864
  await this._saveAndEmit(FromBTCLNSwapState.CLAIM_COMMITED);
664
865
  }
@@ -672,67 +873,77 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
672
873
  * Unsafe txs claim getter without state checking!
673
874
  *
674
875
  * @param _signer
675
- * @private
876
+ * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
877
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
878
+ *
879
+ * @internal
676
880
  */
677
- private async _txsClaim(_signer?: T["Signer"] | T["NativeSigner"]): Promise<T["TX"][]> {
678
- if(this.data==null) throw new Error("Unknown data, wrong state?");
679
- return this.wrapper.contract.txsClaimWithSecret(
881
+ private async _txsClaim(_signer?: T["Signer"] | T["NativeSigner"], secret?: string): Promise<T["TX"][]> {
882
+ if(this._data==null) throw new Error("Unknown data, wrong state?");
883
+ const useSecret = secret ?? this.secret;
884
+ if(useSecret==null)
885
+ throw new Error("Swap secret pre-image not known and not provided, please provide the swap secret pre-image as an argument");
886
+ if(!this.isValidSecretPreimage(useSecret))
887
+ throw new Error("Invalid swap secret pre-image provided!");
888
+
889
+ return this.wrapper._contract.txsClaimWithSecret(
680
890
  _signer==null ?
681
891
  this._getInitiator() :
682
- (isAbstractSigner(_signer) ? _signer : await this.wrapper.chain.wrapSigner(_signer)),
683
- this.data, this.secret, true, true
892
+ (isAbstractSigner(_signer) ? _signer : await this.wrapper._chain.wrapSigner(_signer)),
893
+ this._data, useSecret, true, true
684
894
  );
685
895
  }
686
896
 
687
897
  /**
688
- * Returns transactions required for claiming the HTLC and finishing the swap by revealing the HTLC secret
689
- * (hash preimage)
898
+ * @inheritDoc
690
899
  *
691
900
  * @param _signer Optional signer address to use for claiming the swap, can also be different from the initializer
692
- * @throws {Error} If in invalid state (must be CLAIM_COMMITED)
901
+ * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
902
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
903
+ *
904
+ * @throws {Error} If in invalid state (must be {@link FromBTCLNSwapState.CLAIM_COMMITED})
693
905
  */
694
- async txsClaim(_signer?: T["Signer"] | T["NativeSigner"]): Promise<T["TX"][]> {
695
- if(this.state!==FromBTCLNSwapState.CLAIM_COMMITED) throw new Error("Must be in CLAIM_COMMITED state!");
696
- return this._txsClaim(_signer);
906
+ async txsClaim(_signer?: T["Signer"] | T["NativeSigner"], secret?: string): Promise<T["TX"][]> {
907
+ if(this._state!==FromBTCLNSwapState.CLAIM_COMMITED) throw new Error("Must be in CLAIM_COMMITED state!");
908
+ return this._txsClaim(_signer, secret);
697
909
  }
698
910
 
699
911
  /**
700
- * Claims and finishes the swap
912
+ * @inheritDoc
701
913
  *
702
- * @param _signer Signer to sign the transactions with, can also be different to the initializer
703
- * @param abortSignal Abort signal to stop waiting for transaction confirmation
914
+ * @param _signer
915
+ * @param abortSignal
704
916
  * @param onBeforeTxSent
917
+ * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
918
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
705
919
  */
706
- async claim(_signer: T["Signer"] | T["NativeSigner"], abortSignal?: AbortSignal, onBeforeTxSent?: (txId: string) => void): Promise<string> {
707
- const signer = isAbstractSigner(_signer) ? _signer : await this.wrapper.chain.wrapSigner(_signer);
920
+ async claim(_signer: T["Signer"] | T["NativeSigner"], abortSignal?: AbortSignal, onBeforeTxSent?: (txId: string) => void, secret?: string): Promise<string> {
921
+ const signer = isAbstractSigner(_signer) ? _signer : await this.wrapper._chain.wrapSigner(_signer);
708
922
  let txCount = 0;
709
- const result = await this.wrapper.chain.sendAndConfirm(
710
- signer, await this.txsClaim(), true, abortSignal, undefined, (txId: string) => {
923
+ const result = await this.wrapper._chain.sendAndConfirm(
924
+ signer, await this.txsClaim(_signer, secret), true, abortSignal, undefined, (txId: string) => {
711
925
  txCount++;
712
926
  if(onBeforeTxSent!=null && txCount===1) onBeforeTxSent(txId);
713
927
  return Promise.resolve();
714
928
  }
715
929
  );
716
930
 
717
- this.claimTxId = result[0];
718
- if(this.state===FromBTCLNSwapState.CLAIM_COMMITED || this.state===FromBTCLNSwapState.EXPIRED || this.state===FromBTCLNSwapState.FAILED) {
931
+ this._claimTxId = result[0];
932
+ if(this._state===FromBTCLNSwapState.CLAIM_COMMITED || this._state===FromBTCLNSwapState.EXPIRED || this._state===FromBTCLNSwapState.FAILED) {
719
933
  await this._saveAndEmit(FromBTCLNSwapState.CLAIM_CLAIMED);
720
934
  }
721
935
  return result[0];
722
936
  }
723
937
 
724
938
  /**
725
- * Waits till the swap is successfully claimed
939
+ * @inheritDoc
726
940
  *
727
- * @param maxWaitTimeSeconds Maximum time in seconds to wait for the swap to be settled
728
- * @param abortSignal AbortSignal
729
- * @throws {Error} If swap is in invalid state (must be BTC_TX_CONFIRMED)
941
+ * @throws {Error} If swap is in invalid state (must be {@link FromBTCLNSwapState.CLAIM_COMMITED})
730
942
  * @throws {Error} If the LP refunded sooner than we were able to claim
731
- * @returns {boolean} whether the swap was claimed in time or not
732
943
  */
733
944
  async waitTillClaimed(maxWaitTimeSeconds?: number, abortSignal?: AbortSignal): Promise<boolean> {
734
- if(this.state===FromBTCLNSwapState.CLAIM_CLAIMED) return Promise.resolve(true);
735
- if(this.state!==FromBTCLNSwapState.CLAIM_COMMITED) throw new Error("Invalid state (not CLAIM_COMMITED)");
945
+ if(this._state===FromBTCLNSwapState.CLAIM_CLAIMED) return Promise.resolve(true);
946
+ if(this._state!==FromBTCLNSwapState.CLAIM_COMMITED) throw new Error("Invalid state (not CLAIM_COMMITED)");
736
947
 
737
948
  const abortController = new AbortController();
738
949
  if(abortSignal!=null) abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
@@ -770,17 +981,17 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
770
981
  this.logger.debug("waitTillClaimed(): Resolved from watchdog");
771
982
 
772
983
  if(res?.type===SwapCommitStateType.PAID) {
773
- if((this.state as FromBTCLNSwapState)!==FromBTCLNSwapState.CLAIM_CLAIMED) {
774
- this.claimTxId = await res.getClaimTxId();
984
+ if((this._state as FromBTCLNSwapState)!==FromBTCLNSwapState.CLAIM_CLAIMED) {
985
+ this._claimTxId = await res.getClaimTxId();
775
986
  await this._saveAndEmit(FromBTCLNSwapState.CLAIM_CLAIMED);
776
987
  }
777
988
  }
778
989
  if(res?.type===SwapCommitStateType.NOT_COMMITED || res?.type===SwapCommitStateType.EXPIRED) {
779
990
  if(
780
- (this.state as FromBTCLNSwapState)!==FromBTCLNSwapState.CLAIM_CLAIMED &&
781
- (this.state as FromBTCLNSwapState)!==FromBTCLNSwapState.FAILED
991
+ (this._state as FromBTCLNSwapState)!==FromBTCLNSwapState.CLAIM_CLAIMED &&
992
+ (this._state as FromBTCLNSwapState)!==FromBTCLNSwapState.FAILED
782
993
  ) {
783
- if(res.getRefundTxId!=null) this.refundTxId = await res.getRefundTxId();
994
+ if(res.getRefundTxId!=null) this._refundTxId = await res.getRefundTxId();
784
995
  await this._saveAndEmit(FromBTCLNSwapState.FAILED);
785
996
  }
786
997
  throw new Error("Swap expired while waiting for claim!");
@@ -793,10 +1004,11 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
793
1004
  //// Commit & claim
794
1005
 
795
1006
  /**
796
- * Estimated transaction fee for commit & claim txs combined
1007
+ * Estimated transaction fee for commit & claim transactions combined, required
1008
+ * to settle the swap on the smart chain destination side.
797
1009
  */
798
- async getCommitAndClaimFee(): Promise<bigint> {
799
- const swapContract: T["Contract"] = this.wrapper.contract;
1010
+ async getCommitAndClaimNetworkFee(): Promise<TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true>> {
1011
+ const swapContract: T["Contract"] = this.wrapper._contract;
800
1012
  const feeRate = this.feeRate ?? await swapContract.getInitFeeRate(
801
1013
  this.getSwapData().getOfferer(),
802
1014
  this.getSwapData().getClaimer(),
@@ -813,35 +1025,53 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
813
1025
  swapContract.getRawClaimFee(this._getInitiator(), this.getSwapData(), feeRate) :
814
1026
  swapContract.getClaimFee(this._getInitiator(), this.getSwapData(), feeRate)
815
1027
  );
816
- return commitFee + claimFee;
1028
+
1029
+ return toTokenAmount(
1030
+ commitFee + claimFee,
1031
+ this.wrapper._getNativeToken(),
1032
+ this.wrapper._prices
1033
+ );
817
1034
  }
818
1035
 
1036
+ /**
1037
+ * Returns whether the underlying chain supports calling commit and claim in a single call,
1038
+ * such that you can use the {@link commitAndClaim} function. If not you have to manually
1039
+ * call {@link commit} first and then {@link claim}.
1040
+ */
819
1041
  canCommitAndClaimInOneShot(): boolean {
820
- return this.wrapper.contract.initAndClaimWithSecret!=null;
1042
+ return this.wrapper._contract.initAndClaimWithSecret!=null;
821
1043
  }
822
1044
 
823
1045
  /**
824
1046
  * Returns transactions for both commit & claim operation together, such that they can be signed all at once by
825
- * the wallet. CAUTION: transactions must be sent sequentially, such that the claim (2nd) transaction is only
1047
+ * the wallet. **WARNING**: transactions must be sent sequentially, such that the claim (2nd) transaction is only
826
1048
  * sent after the commit (1st) transaction confirms. Failure to do so can reveal the HTLC pre-image too soon,
827
- * opening a possibility for the LP to steal funds.
1049
+ * opening a possibility for the LP to steal funds!
828
1050
  *
829
1051
  * @param skipChecks Skip checks like making sure init signature is still valid and swap wasn't commited yet
830
1052
  * (this is handled when swap is created (quoted), if you commit right after quoting, you can use skipChecks=true)
1053
+ * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
1054
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
831
1055
  *
832
1056
  * @throws {Error} If in invalid state (must be PR_PAID or CLAIM_COMMITED)
833
1057
  */
834
- async txsCommitAndClaim(skipChecks?: boolean): Promise<T["TX"][]> {
835
- if(this.state===FromBTCLNSwapState.CLAIM_COMMITED) return await this.txsClaim();
1058
+ async txsCommitAndClaim(skipChecks?: boolean, secret?: string): Promise<T["TX"][]> {
1059
+ if(this._state===FromBTCLNSwapState.CLAIM_COMMITED) return await this.txsClaim(undefined, secret);
836
1060
  if(
837
- this.state!==FromBTCLNSwapState.PR_PAID &&
838
- (this.state!==FromBTCLNSwapState.QUOTE_SOFT_EXPIRED || this.signatureData==null)
1061
+ this._state!==FromBTCLNSwapState.PR_PAID &&
1062
+ (this._state!==FromBTCLNSwapState.QUOTE_SOFT_EXPIRED || this.signatureData==null)
839
1063
  ) throw new Error("Must be in PR_PAID state!");
840
- if(this.data==null) throw new Error("Unknown data, wrong state?");
1064
+ if(this._data==null) throw new Error("Unknown data, wrong state?");
1065
+
1066
+ const useSecret = secret ?? this.secret;
1067
+ if(useSecret==null)
1068
+ throw new Error("Swap secret pre-image not known and not provided, please provide the swap secret pre-image as second argument");
1069
+ if(!this.isValidSecretPreimage(useSecret))
1070
+ throw new Error("Invalid swap secret pre-image provided!");
841
1071
 
842
1072
  const initTxs = await this.txsCommit(skipChecks);
843
- const claimTxs = await this.wrapper.contract.txsClaimWithSecret(
844
- this._getInitiator(), this.data, this.secret,
1073
+ const claimTxs = await this.wrapper._contract.txsClaimWithSecret(
1074
+ this._getInitiator(), this._data, useSecret,
845
1075
  true, true, undefined,
846
1076
  true
847
1077
  );
@@ -850,30 +1080,37 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
850
1080
  }
851
1081
 
852
1082
  /**
853
- * Commits and claims the swap, in a way that the transactions can be signed together by the underlying provider and
854
- * then sent sequentially
1083
+ * Commits and claims the swap, in a way that the transactions can be signed together by the provided signer and
1084
+ * then automatically sent sequentially by the SDK. To check if the underlying chain supports this flow check
1085
+ * the {@link canCommitAndClaimInOneShot} function.
855
1086
  *
856
1087
  * @param _signer Signer to sign the transactions with, must be the same as used in the initialization
857
1088
  * @param abortSignal Abort signal to stop waiting for the transaction confirmation and abort
858
1089
  * @param skipChecks Skip checks like making sure init signature is still valid and swap wasn't commited yet
859
1090
  * (this is handled when swap is created (quoted), if you commit right after quoting, you can use skipChecks=true)
860
- * @param onBeforeCommitTxSent
861
- * @param onBeforeClaimTxSent
1091
+ * @param onBeforeCommitTxSent Optional callback called before the initialization (commit) transaction is
1092
+ * broadcasted
1093
+ * @param onBeforeClaimTxSent Optional callback called before the settlement (claim) transaction is
1094
+ * broadcasted
1095
+ * @param secret A swap secret to use for the claim transaction, generally only needed if the swap
1096
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
1097
+ *
862
1098
  * @throws {Error} If in invalid state (must be PR_PAID or CLAIM_COMMITED)
863
1099
  * @throws {Error} If invalid signer is provided that doesn't match the swap data
864
1100
  */
865
1101
  async commitAndClaim(
866
1102
  _signer: T["Signer"] | T["NativeSigner"], abortSignal?: AbortSignal, skipChecks?: boolean,
867
- onBeforeCommitTxSent?: (txId: string) => void, onBeforeClaimTxSent?: (txId: string) => void
1103
+ onBeforeCommitTxSent?: (txId: string) => void, onBeforeClaimTxSent?: (txId: string) => void,
1104
+ secret?: string
868
1105
  ): Promise<string[]> {
869
- const signer = isAbstractSigner(_signer) ? _signer : await this.wrapper.chain.wrapSigner(_signer);
1106
+ const signer = isAbstractSigner(_signer) ? _signer : await this.wrapper._chain.wrapSigner(_signer);
870
1107
  if(!this.canCommitAndClaimInOneShot()) throw new Error("Cannot commitAndClaim in single action, please run commit and claim separately!");
871
1108
  this.checkSigner(signer);
872
- if(this.state===FromBTCLNSwapState.CLAIM_COMMITED) return [await this.claim(signer, abortSignal, onBeforeClaimTxSent)];
1109
+ if(this._state===FromBTCLNSwapState.CLAIM_COMMITED) return [await this.claim(signer, abortSignal, onBeforeClaimTxSent, secret)];
873
1110
 
874
1111
  let txCount = 0;
875
- const txs = await this.txsCommitAndClaim(skipChecks);
876
- const result = await this.wrapper.chain.sendAndConfirm(
1112
+ const txs = await this.txsCommitAndClaim(skipChecks, secret);
1113
+ const result = await this.wrapper._chain.sendAndConfirm(
877
1114
  signer, txs, true, abortSignal, undefined, (txId: string) => {
878
1115
  txCount++;
879
1116
  if(onBeforeCommitTxSent!=null && txCount===1) onBeforeCommitTxSent(txId);
@@ -882,9 +1119,9 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
882
1119
  }
883
1120
  );
884
1121
 
885
- this.commitTxId = result[0] ?? this.commitTxId;
886
- this.claimTxId = result[result.length-1] ?? this.claimTxId;
887
- if(this.state!==FromBTCLNSwapState.CLAIM_CLAIMED) {
1122
+ this._commitTxId = result[0] ?? this._commitTxId;
1123
+ this._claimTxId = result[result.length-1] ?? this._claimTxId;
1124
+ if(this._state!==FromBTCLNSwapState.CLAIM_CLAIMED) {
888
1125
  await this._saveAndEmit(FromBTCLNSwapState.CLAIM_CLAIMED);
889
1126
  }
890
1127
 
@@ -896,23 +1133,33 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
896
1133
  //// LNURL
897
1134
 
898
1135
  /**
899
- * Is this an LNURL-withdraw swap?
1136
+ * Whether this swap uses an LNURL-withdraw link
900
1137
  */
901
1138
  isLNURL(): boolean {
902
1139
  return this.lnurl!=null;
903
1140
  }
904
1141
 
905
1142
  /**
906
- * Gets the used LNURL or null if this is not an LNURL-withdraw swap
1143
+ * Gets the used LNURL or `null` if this is not an LNURL-withdraw swap
907
1144
  */
908
1145
  getLNURL(): string | null {
909
1146
  return this.lnurl ?? null;
910
1147
  }
911
1148
 
912
1149
  /**
913
- * Pay the generated lightning network invoice with LNURL-withdraw
1150
+ * Pay the generated lightning network invoice with an LNURL-withdraw link, this
1151
+ * is useful when you want to display a lightning payment QR code and also want to
1152
+ * allow payments using LNURL-withdraw NFC cards.
1153
+ *
1154
+ * Note that the swap needs to be created **without** an LNURL to begin with for this function
1155
+ * to work. If this swap is already using an LNURL-withdraw link, this function throws.
914
1156
  */
915
1157
  async settleWithLNURLWithdraw(lnurl: string | LNURLWithdraw): Promise<void> {
1158
+ if(
1159
+ this._state!==FromBTCLNSwapState.PR_CREATED &&
1160
+ (this._state!==FromBTCLNSwapState.QUOTE_SOFT_EXPIRED || this.signatureData!=null)
1161
+ ) throw new Error("Must be in PR_CREATED state!");
1162
+
916
1163
  if(this.lnurl!=null) throw new Error("Cannot settle LNURL-withdraw swap with different LNURL");
917
1164
  let lnurlParams: LNURLWithdrawParamsWithUrl;
918
1165
  if(typeof(lnurl)==="string") {
@@ -923,6 +1170,10 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
923
1170
  } else {
924
1171
  lnurlParams = lnurl.params;
925
1172
  }
1173
+
1174
+ if(this.pr==null || !this.pr.toLowerCase().startsWith("ln"))
1175
+ throw new Error("Input lightning network invoice not available, the swap was probably recovered!");
1176
+
926
1177
  LNURL.useLNURLWithdraw(lnurlParams, this.pr).catch(e => this.lnurlFailSignal.abort(e));
927
1178
  this.lnurl = lnurlParams.url;
928
1179
  this.lnurlCallback = lnurlParams.callback;
@@ -935,6 +1186,9 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
935
1186
  //////////////////////////////
936
1187
  //// Storage
937
1188
 
1189
+ /**
1190
+ * @inheritDoc
1191
+ */
938
1192
  serialize(): any {
939
1193
  return {
940
1194
  ...super.serialize(),
@@ -944,7 +1198,8 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
944
1198
  lnurlK1: this.lnurlK1,
945
1199
  lnurlCallback: this.lnurlCallback,
946
1200
  prPosted: this.prPosted,
947
- initialSwapData: this.initialSwapData.serialize()
1201
+ initialSwapData: this.initialSwapData.serialize(),
1202
+ usesClaimHashAsId: this.usesClaimHashAsId
948
1203
  };
949
1204
  }
950
1205
 
@@ -959,76 +1214,69 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
959
1214
  * @private
960
1215
  */
961
1216
  private async syncStateFromChain(quoteDefinitelyExpired?: boolean, commitStatus?: SwapCommitState): Promise<boolean> {
962
- //Check for expiry before the getCommitStatus to prevent race conditions
963
- let quoteExpired: boolean = false;
964
- if(this.state===FromBTCLNSwapState.PR_PAID || (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null)) {
965
- quoteExpired = quoteDefinitelyExpired ?? await this._verifyQuoteDefinitelyExpired();
966
- }
967
-
968
- if(this.state===FromBTCLNSwapState.CLAIM_COMMITED || this.state===FromBTCLNSwapState.EXPIRED) {
969
- //Check if it's already successfully paid
970
- commitStatus ??= await this.wrapper.contract.getCommitStatus(this._getInitiator(), this.data!);
971
- if(commitStatus?.type===SwapCommitStateType.PAID) {
972
- if(this.claimTxId==null) this.claimTxId = await commitStatus.getClaimTxId();
973
- this.state = FromBTCLNSwapState.CLAIM_CLAIMED;
974
- return true;
1217
+ if(
1218
+ this._state===FromBTCLNSwapState.PR_PAID ||
1219
+ (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null) ||
1220
+ this._state===FromBTCLNSwapState.CLAIM_COMMITED ||
1221
+ this._state===FromBTCLNSwapState.EXPIRED
1222
+ ) {
1223
+ //Check for expiry before the getCommitStatus to prevent race conditions
1224
+ let quoteExpired: boolean = false;
1225
+ if(this._state===FromBTCLNSwapState.PR_PAID || (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null)) {
1226
+ quoteExpired = quoteDefinitelyExpired ?? await this._verifyQuoteDefinitelyExpired();
975
1227
  }
976
1228
 
977
- if(commitStatus?.type===SwapCommitStateType.NOT_COMMITED || commitStatus?.type===SwapCommitStateType.EXPIRED) {
978
- if(this.refundTxId==null && commitStatus.getRefundTxId) this.refundTxId = await commitStatus.getRefundTxId();
979
- this.state = FromBTCLNSwapState.FAILED;
980
- return true;
981
- }
982
- }
1229
+ //Check if it's already successfully paid
1230
+ commitStatus ??= await this.wrapper._contract.getCommitStatus(this._getInitiator(), this._data!);
1231
+ if(commitStatus!=null && await this._forciblySetOnchainState(commitStatus)) return true;
983
1232
 
984
- if(this.state===FromBTCLNSwapState.PR_PAID || (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null)) {
985
- //Check if it's already committed
986
- commitStatus ??= await this.wrapper.contract.getCommitStatus(this._getInitiator(), this.data!);
987
- switch(commitStatus?.type) {
988
- case SwapCommitStateType.COMMITED:
989
- this.state = FromBTCLNSwapState.CLAIM_COMMITED;
990
- return true;
991
- case SwapCommitStateType.EXPIRED:
992
- if(this.refundTxId==null && commitStatus.getRefundTxId) this.refundTxId = await commitStatus.getRefundTxId();
993
- this.state = FromBTCLNSwapState.QUOTE_EXPIRED;
1233
+ //Set the state on expiry here
1234
+ if(this._state===FromBTCLNSwapState.PR_PAID || (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null)) {
1235
+ if(quoteExpired) {
1236
+ this._state = FromBTCLNSwapState.QUOTE_EXPIRED;
994
1237
  return true;
995
- case SwapCommitStateType.PAID:
996
- if(this.claimTxId==null && commitStatus.getClaimTxId) this.claimTxId = await commitStatus.getClaimTxId();
997
- this.state = FromBTCLNSwapState.CLAIM_CLAIMED;
998
- return true;
999
- }
1000
- }
1001
-
1002
- //Set the state on expiry here
1003
- if(this.state===FromBTCLNSwapState.PR_PAID || (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null)) {
1004
- if(quoteExpired) {
1005
- this.state = FromBTCLNSwapState.QUOTE_EXPIRED;
1006
- return true;
1238
+ }
1007
1239
  }
1008
1240
  }
1009
-
1010
1241
  return false;
1011
1242
  }
1012
1243
 
1244
+ /**
1245
+ * @inheritDoc
1246
+ * @internal
1247
+ */
1013
1248
  _shouldFetchExpiryStatus(): boolean {
1014
- return this.state===FromBTCLNSwapState.PR_PAID || (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null);
1249
+ return this._state===FromBTCLNSwapState.PR_PAID || (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null);
1015
1250
  }
1016
1251
 
1017
- _shouldFetchCommitStatus(): boolean {
1018
- return this.state===FromBTCLNSwapState.PR_PAID || (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null) ||
1019
- this.state===FromBTCLNSwapState.CLAIM_COMMITED || this.state===FromBTCLNSwapState.EXPIRED;
1252
+ /**
1253
+ * @inheritDoc
1254
+ * @internal
1255
+ */
1256
+ _shouldFetchOnchainState(): boolean {
1257
+ return this._state===FromBTCLNSwapState.PR_PAID || (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData!=null) ||
1258
+ this._state===FromBTCLNSwapState.CLAIM_COMMITED || this._state===FromBTCLNSwapState.EXPIRED;
1020
1259
  }
1021
1260
 
1261
+ /**
1262
+ * Whether an intermediary (LP) should be contacted to get the state of this swap.
1263
+ *
1264
+ * @internal
1265
+ */
1022
1266
  _shouldCheckIntermediary(): boolean {
1023
- return this.state===FromBTCLNSwapState.PR_CREATED || (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData==null);
1267
+ return this._state===FromBTCLNSwapState.PR_CREATED || (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData==null);
1024
1268
  }
1025
1269
 
1270
+ /**
1271
+ * @inheritDoc
1272
+ * @internal
1273
+ */
1026
1274
  async _sync(save?: boolean, quoteDefinitelyExpired?: boolean, commitStatus?: SwapCommitState, skipLpCheck?: boolean): Promise<boolean> {
1027
1275
  let changed = false;
1028
1276
 
1029
- if(this.state===FromBTCLNSwapState.PR_CREATED || (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData==null)) {
1030
- if(this.state!=FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.getTimeoutTime()<Date.now()) {
1031
- this.state = FromBTCLNSwapState.QUOTE_SOFT_EXPIRED;
1277
+ if(this._state===FromBTCLNSwapState.PR_CREATED || (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData==null)) {
1278
+ if(this._state!=FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.getTimeoutTime()<Date.now()) {
1279
+ this._state = FromBTCLNSwapState.QUOTE_SOFT_EXPIRED;
1032
1280
  changed ||= true;
1033
1281
  }
1034
1282
 
@@ -1039,9 +1287,9 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
1039
1287
  this.logger.error("_sync(): Failed to synchronize swap, error: ", e);
1040
1288
  }
1041
1289
 
1042
- if(this.state===FromBTCLNSwapState.PR_CREATED || (this.state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData==null)) {
1290
+ if(this._state===FromBTCLNSwapState.PR_CREATED || (this._state===FromBTCLNSwapState.QUOTE_SOFT_EXPIRED && this.signatureData==null)) {
1043
1291
  if(await this._verifyQuoteDefinitelyExpired()) {
1044
- this.state = FromBTCLNSwapState.QUOTE_EXPIRED;
1292
+ this._state = FromBTCLNSwapState.QUOTE_EXPIRED;
1045
1293
  changed ||= true;
1046
1294
  }
1047
1295
  }
@@ -1049,31 +1297,75 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
1049
1297
 
1050
1298
  if(await this.syncStateFromChain(quoteDefinitelyExpired, commitStatus)) changed = true;
1051
1299
 
1300
+ if(this._state===FromBTCLNSwapState.CLAIM_COMMITED) {
1301
+ const expired = await this.wrapper._contract.isExpired(this._getInitiator(), this._data!);
1302
+ if(expired) {
1303
+ this._state = FromBTCLNSwapState.EXPIRED;
1304
+ changed = true;
1305
+ }
1306
+ }
1307
+
1052
1308
  if(save && changed) await this._saveAndEmit();
1053
1309
 
1054
1310
  return changed;
1055
1311
  }
1056
1312
 
1313
+ /**
1314
+ * @inheritDoc
1315
+ * @internal
1316
+ */
1317
+ async _forciblySetOnchainState(commitStatus: SwapCommitState): Promise<boolean> {
1318
+ switch(commitStatus.type) {
1319
+ case SwapCommitStateType.PAID:
1320
+ if(this._claimTxId==null) this._claimTxId = await commitStatus.getClaimTxId();
1321
+ if(this.secret==null || this.pr==null) this._setSwapSecret(await commitStatus.getClaimResult());
1322
+ this._state = FromBTCLNSwapState.CLAIM_CLAIMED;
1323
+ return true;
1324
+ case SwapCommitStateType.NOT_COMMITED:
1325
+ if(this._refundTxId==null && commitStatus.getRefundTxId) this._refundTxId = await commitStatus.getRefundTxId();
1326
+ if(this._refundTxId!=null) {
1327
+ this._state = FromBTCLNSwapState.FAILED;
1328
+ return true;
1329
+ }
1330
+ break;
1331
+ case SwapCommitStateType.EXPIRED:
1332
+ if(this._refundTxId==null && commitStatus.getRefundTxId) this._refundTxId = await commitStatus.getRefundTxId();
1333
+ this._state = this._refundTxId==null ? FromBTCLNSwapState.QUOTE_EXPIRED : FromBTCLNSwapState.FAILED;
1334
+ return true;
1335
+ case SwapCommitStateType.COMMITED:
1336
+ if(this._state!==FromBTCLNSwapState.CLAIM_COMMITED && this._state!==FromBTCLNSwapState.EXPIRED) {
1337
+ this._state = FromBTCLNSwapState.CLAIM_COMMITED;
1338
+ return true;
1339
+ }
1340
+ break;
1341
+ }
1342
+ return false;
1343
+ }
1344
+
1345
+ /**
1346
+ * @inheritDoc
1347
+ * @internal
1348
+ */
1057
1349
  async _tick(save?: boolean): Promise<boolean> {
1058
- switch(this.state) {
1350
+ switch(this._state) {
1059
1351
  case FromBTCLNSwapState.PR_CREATED:
1060
1352
  if(this.getTimeoutTime()<Date.now()) {
1061
- this.state = FromBTCLNSwapState.QUOTE_SOFT_EXPIRED;
1353
+ this._state = FromBTCLNSwapState.QUOTE_SOFT_EXPIRED;
1062
1354
  if(save) await this._saveAndEmit();
1063
1355
  return true;
1064
1356
  }
1065
1357
  break;
1066
1358
  case FromBTCLNSwapState.PR_PAID:
1067
1359
  if(this.expiry<Date.now()) {
1068
- this.state = FromBTCLNSwapState.QUOTE_SOFT_EXPIRED;
1360
+ this._state = FromBTCLNSwapState.QUOTE_SOFT_EXPIRED;
1069
1361
  if(save) await this._saveAndEmit();
1070
1362
  return true;
1071
1363
  }
1072
1364
  break;
1073
1365
  case FromBTCLNSwapState.CLAIM_COMMITED:
1074
- const expired = await this.wrapper.contract.isExpired(this._getInitiator(), this.data!);
1366
+ const expired = await this.wrapper._contract.isExpired(this._getInitiator(), this._data!);
1075
1367
  if(expired) {
1076
- this.state = FromBTCLNSwapState.EXPIRED;
1368
+ this._state = FromBTCLNSwapState.EXPIRED;
1077
1369
  if(save) await this._saveAndEmit();
1078
1370
  return true;
1079
1371
  }
@@ -1083,4 +1375,16 @@ export class FromBTCLNSwap<T extends ChainType = ChainType>
1083
1375
  return false;
1084
1376
  }
1085
1377
 
1378
+ /**
1379
+ * Forcibly sets the swap secret pre-image from on-chain data
1380
+ *
1381
+ * @internal
1382
+ */
1383
+ _setSwapSecret(secret: string) {
1384
+ this.secret = secret;
1385
+ if(this.pr==null) {
1386
+ this.pr = Buffer.from(sha256(Buffer.from(secret, "hex"))).toString("hex");
1387
+ }
1388
+ }
1389
+
1086
1390
  }