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