@atomiqlabs/sdk 8.1.7 → 8.3.1

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