@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
@@ -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,6 +39,7 @@ 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
@@ -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
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,81 @@ 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
+ * @inheritDoc
797
1069
  *
798
1070
  * @param maxWaitTimeSeconds Maximum time in seconds to wait for the swap to be settled
799
1071
  * @param abortSignal AbortSignal
800
- * @throws {Error} If swap is in invalid state (must be BTC_TX_CONFIRMED)
1072
+ * @param secret A swap secret to broadcast to watchtowers, generally only needed if the swap
1073
+ * was recovered from on-chain data, or the pre-image was generated outside the SDK
1074
+ *
1075
+ * @throws {Error} If swap is in invalid state (must be {@link FromBTCLNAutoSwapState.CLAIM_COMMITED})
801
1076
  * @throws {Error} If the LP refunded sooner than we were able to claim
802
1077
  * @returns {boolean} whether the swap was claimed in time or not
803
1078
  */
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)");
1079
+ async waitTillClaimed(maxWaitTimeSeconds?: number, abortSignal?: AbortSignal, secret?: string): Promise<boolean> {
1080
+ if(this._state===FromBTCLNAutoSwapState.CLAIM_CLAIMED) return Promise.resolve(true);
1081
+ if(this._state!==FromBTCLNAutoSwapState.CLAIM_COMMITED) throw new Error("Invalid state (not CLAIM_COMMITED)");
1082
+
1083
+ if(secret!=null) {
1084
+ if(!this.isValidSecretPreimage(secret))
1085
+ throw new Error("Invalid swap secret pre-image provided!");
1086
+ this.secret = secret;
1087
+ }
807
1088
 
808
1089
  const abortController = new AbortController();
809
1090
  if(abortSignal!=null) abortSignal.addEventListener("abort", () => abortController.abort(abortSignal.reason));
@@ -841,15 +1122,15 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
841
1122
  this.logger.debug("waitTillClaimed(): Resolved from watchdog");
842
1123
 
843
1124
  if(res?.type===SwapCommitStateType.PAID) {
844
- if((this.state as FromBTCLNAutoSwapState)!==FromBTCLNAutoSwapState.CLAIM_CLAIMED) {
845
- this.claimTxId = await res.getClaimTxId();
1125
+ if((this._state as FromBTCLNAutoSwapState)!==FromBTCLNAutoSwapState.CLAIM_CLAIMED) {
1126
+ this._claimTxId = await res.getClaimTxId();
846
1127
  await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_CLAIMED);
847
1128
  }
848
1129
  }
849
1130
  if(res?.type===SwapCommitStateType.NOT_COMMITED || res?.type===SwapCommitStateType.EXPIRED) {
850
1131
  if(
851
- (this.state as FromBTCLNAutoSwapState)!==FromBTCLNAutoSwapState.CLAIM_CLAIMED &&
852
- (this.state as FromBTCLNAutoSwapState)!==FromBTCLNAutoSwapState.FAILED
1132
+ (this._state as FromBTCLNAutoSwapState)!==FromBTCLNAutoSwapState.CLAIM_CLAIMED &&
1133
+ (this._state as FromBTCLNAutoSwapState)!==FromBTCLNAutoSwapState.FAILED
853
1134
  ) {
854
1135
  await this._saveAndEmit(FromBTCLNAutoSwapState.FAILED);
855
1136
  }
@@ -863,23 +1144,33 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
863
1144
  //// LNURL
864
1145
 
865
1146
  /**
866
- * Is this an LNURL-withdraw swap?
1147
+ * Whether this swap uses an LNURL-withdraw link
867
1148
  */
868
1149
  isLNURL(): boolean {
869
1150
  return this.lnurl!=null;
870
1151
  }
871
1152
 
872
1153
  /**
873
- * Gets the used LNURL or null if this is not an LNURL-withdraw swap
1154
+ * Gets the used LNURL or `null` if this is not an LNURL-withdraw swap
874
1155
  */
875
1156
  getLNURL(): string | null {
876
1157
  return this.lnurl ?? null;
877
1158
  }
878
1159
 
879
1160
  /**
880
- * Pay the generated lightning network invoice with LNURL-withdraw
1161
+ * Pay the generated lightning network invoice with an LNURL-withdraw link, this
1162
+ * is useful when you want to display a lightning payment QR code and also want to
1163
+ * allow payments using LNURL-withdraw NFC cards.
1164
+ *
1165
+ * Note that the swap needs to be created **without** an LNURL to begin with for this function
1166
+ * to work. If this swap is already using an LNURL-withdraw link, this function throws.
881
1167
  */
882
1168
  async settleWithLNURLWithdraw(lnurl: string | LNURLWithdraw): Promise<void> {
1169
+ if(
1170
+ this._state!==FromBTCLNAutoSwapState.PR_CREATED &&
1171
+ this._state!==FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED
1172
+ ) throw new Error("Must be in PR_CREATED state!");
1173
+
883
1174
  if(this.lnurl!=null) throw new Error("Cannot settle LNURL-withdraw swap with different LNURL");
884
1175
  let lnurlParams: LNURLWithdrawParamsWithUrl;
885
1176
  if(typeof(lnurl)==="string") {
@@ -890,6 +1181,10 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
890
1181
  } else {
891
1182
  lnurlParams = lnurl.params;
892
1183
  }
1184
+
1185
+ if(this.pr==null || !this.pr.toLowerCase().startsWith("ln"))
1186
+ throw new Error("Input lightning network invoice not available, the swap was probably recovered!");
1187
+
893
1188
  LNURL.useLNURLWithdraw(lnurlParams, this.pr).catch(e => this.lnurlFailSignal.abort(e));
894
1189
  this.lnurl = lnurlParams.url;
895
1190
  this.lnurlCallback = lnurlParams.callback;
@@ -902,12 +1197,15 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
902
1197
  //////////////////////////////
903
1198
  //// Storage
904
1199
 
1200
+ /**
1201
+ * @inheritDoc
1202
+ */
905
1203
  serialize(): any {
906
1204
  return {
907
1205
  ...super.serialize(),
908
- data: this.data==null ? null : this.data.serialize(),
909
- commitTxId: this.commitTxId,
910
- claimTxId: this.claimTxId,
1206
+ data: this._data==null ? null : this._data.serialize(),
1207
+ commitTxId: this._commitTxId,
1208
+ claimTxId: this._claimTxId,
911
1209
  btcAmountSwap: this.btcAmountSwap==null ? null : this.btcAmountSwap.toString(10),
912
1210
  btcAmountGas: this.btcAmountGas==null ? null : this.btcAmountGas.toString(10),
913
1211
  gasSwapFeeBtc: this.gasSwapFeeBtc==null ? null : this.gasSwapFeeBtc.toString(10),
@@ -919,7 +1217,8 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
919
1217
  lnurlK1: this.lnurlK1,
920
1218
  lnurlCallback: this.lnurlCallback,
921
1219
  prPosted: this.prPosted,
922
- initialSwapData: this.initialSwapData.serialize()
1220
+ initialSwapData: this.initialSwapData.serialize(),
1221
+ usesClaimHashAsId: this.usesClaimHashAsId
923
1222
  };
924
1223
  }
925
1224
 
@@ -934,69 +1233,66 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
934
1233
  * @private
935
1234
  */
936
1235
  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;
1236
+ if(
1237
+ this._state===FromBTCLNAutoSwapState.PR_PAID ||
1238
+ this._state===FromBTCLNAutoSwapState.CLAIM_COMMITED ||
1239
+ this._state===FromBTCLNAutoSwapState.EXPIRED
1240
+ ) {
1241
+ //Check for expiry before the getCommitStatus to prevent race conditions
1242
+ let quoteExpired: boolean = false;
1243
+ if(this._state===FromBTCLNAutoSwapState.PR_PAID) {
1244
+ quoteExpired = quoteDefinitelyExpired ?? await this._verifyQuoteDefinitelyExpired();
950
1245
  }
951
1246
 
952
- if(commitStatus?.type===SwapCommitStateType.NOT_COMMITED || commitStatus?.type===SwapCommitStateType.EXPIRED) {
953
- this.state = FromBTCLNAutoSwapState.FAILED;
954
- return true;
955
- }
956
- }
1247
+ //Check if it's already successfully paid
1248
+ commitStatus ??= await this.wrapper._contract.getCommitStatus(this._getInitiator(), this._data!);
1249
+ if(commitStatus!=null && await this._forciblySetOnchainState(commitStatus)) return true;
957
1250
 
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;
1251
+ if(this._state===FromBTCLNAutoSwapState.PR_PAID) {
1252
+ if(quoteExpired) {
1253
+ this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
971
1254
  return true;
972
- }
973
- if(quoteExpired) {
974
- this.state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
975
- return true;
1255
+ }
976
1256
  }
977
1257
  }
978
1258
 
979
1259
  return false;
980
1260
  }
981
1261
 
982
- _shouldFetchCommitStatus(): boolean {
983
- return this.state===FromBTCLNAutoSwapState.PR_PAID || this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED || this.state===FromBTCLNAutoSwapState.EXPIRED;
1262
+ /**
1263
+ * @inheritDoc
1264
+ * @internal
1265
+ */
1266
+ _shouldFetchOnchainState(): boolean {
1267
+ return this._state===FromBTCLNAutoSwapState.PR_PAID || this._state===FromBTCLNAutoSwapState.CLAIM_COMMITED || this._state===FromBTCLNAutoSwapState.EXPIRED;
984
1268
  }
985
1269
 
1270
+ /**
1271
+ * @inheritDoc
1272
+ * @internal
1273
+ */
986
1274
  _shouldFetchExpiryStatus(): boolean {
987
- return this.state===FromBTCLNAutoSwapState.PR_PAID;
1275
+ return this._state===FromBTCLNAutoSwapState.PR_PAID;
988
1276
  }
989
1277
 
1278
+ /**
1279
+ * @inheritDoc
1280
+ * @internal
1281
+ */
990
1282
  _shouldCheckIntermediary(): boolean {
991
- return this.state===FromBTCLNAutoSwapState.PR_CREATED || this.state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1283
+ return this._state===FromBTCLNAutoSwapState.PR_CREATED || this._state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
992
1284
  }
993
1285
 
1286
+ /**
1287
+ * @inheritDoc
1288
+ * @internal
1289
+ */
994
1290
  async _sync(save?: boolean, quoteDefinitelyExpired?: boolean, commitStatus?: SwapCommitState, skipLpCheck?: boolean): Promise<boolean> {
995
1291
  let changed = false;
996
1292
 
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;
1293
+ if(this._state===FromBTCLNAutoSwapState.PR_CREATED || this._state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
1294
+ if(this._state!==FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED && this.getQuoteExpiry()<Date.now()) {
1295
+ this._state = FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1000
1296
  changed ||= true;
1001
1297
  }
1002
1298
 
@@ -1007,9 +1303,9 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
1007
1303
  this.logger.error("_sync(): Failed to synchronize swap, error: ", e);
1008
1304
  }
1009
1305
 
1010
- if(this.state===FromBTCLNAutoSwapState.PR_CREATED || this.state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
1306
+ if(this._state===FromBTCLNAutoSwapState.PR_CREATED || this._state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED) {
1011
1307
  if(await this._verifyQuoteDefinitelyExpired()) {
1012
- this.state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1308
+ this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1013
1309
  changed ||= true;
1014
1310
  }
1015
1311
  }
@@ -1017,54 +1313,110 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
1017
1313
 
1018
1314
  if(await this.syncStateFromChain(quoteDefinitelyExpired, commitStatus)) changed = true;
1019
1315
 
1316
+ if(this._state===FromBTCLNAutoSwapState.CLAIM_COMMITED) {
1317
+ const expired = await this.wrapper._contract.isExpired(this._getInitiator(), this._data!);
1318
+ if(expired) {
1319
+ this._state = FromBTCLNAutoSwapState.EXPIRED;
1320
+ changed = true;
1321
+ }
1322
+ }
1323
+
1020
1324
  if(save && changed) await this._saveAndEmit();
1021
1325
 
1022
- if(this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED) await this._broadcastSecret().catch(e => {
1326
+ if(this._state===FromBTCLNAutoSwapState.CLAIM_COMMITED && this.secret!=null) await this._broadcastSecret().catch(e => {
1023
1327
  this.logger.error("_sync(): Error when broadcasting swap secret: ", e);
1024
1328
  });
1025
1329
 
1026
1330
  return changed;
1027
1331
  }
1028
1332
 
1029
- private broadcastTickCounter: number = 0;
1333
+ /**
1334
+ * @inheritDoc
1335
+ * @internal
1336
+ */
1337
+ async _forciblySetOnchainState(commitStatus: SwapCommitState): Promise<boolean> {
1338
+ switch(commitStatus?.type) {
1339
+ case SwapCommitStateType.PAID:
1340
+ if(this._claimTxId==null) this._claimTxId = await commitStatus.getClaimTxId();
1341
+ if(this.secret==null || this.pr==null) this._setSwapSecret(await commitStatus.getClaimResult());
1342
+ this._state = FromBTCLNAutoSwapState.CLAIM_CLAIMED;
1343
+ return true;
1344
+ case SwapCommitStateType.NOT_COMMITED:
1345
+ if(this._refundTxId==null && commitStatus.getRefundTxId!=null) this._refundTxId = await commitStatus.getRefundTxId();
1346
+ if(this._refundTxId!=null) {
1347
+ this._state = FromBTCLNAutoSwapState.FAILED;
1348
+ return true;
1349
+ }
1350
+ break;
1351
+ case SwapCommitStateType.EXPIRED:
1352
+ if(this._refundTxId==null && commitStatus.getRefundTxId!=null) this._refundTxId = await commitStatus.getRefundTxId();
1353
+ this._state = this._refundTxId==null ? FromBTCLNAutoSwapState.QUOTE_EXPIRED : FromBTCLNAutoSwapState.FAILED;
1354
+ return true;
1355
+ case SwapCommitStateType.COMMITED:
1356
+ if(this._state!==FromBTCLNAutoSwapState.CLAIM_COMMITED && this._state!==FromBTCLNAutoSwapState.EXPIRED) {
1357
+ this._state = FromBTCLNAutoSwapState.CLAIM_COMMITED;
1358
+ return true;
1359
+ }
1360
+ break;
1361
+ }
1362
+ return false;
1363
+ }
1030
1364
 
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?");
1365
+ /**
1366
+ * Broadcasts the swap secret to the underlying data propagation layer (e.g. Nostr by default)
1367
+ *
1368
+ * @param noCheckExpiry Whether a swap expiration check should be skipped broadcasting
1369
+ * @param secret An optional secret pre-image for the swap to broadcast
1370
+ *
1371
+ * @internal
1372
+ */
1373
+ async _broadcastSecret(noCheckExpiry?: boolean, secret?: string): Promise<void> {
1374
+ if(this._state!==FromBTCLNAutoSwapState.CLAIM_COMMITED) throw new Error("Must be in CLAIM_COMMITED state to broadcast swap secret!");
1375
+ if(this._data==null) throw new Error("Unknown data, wrong state?");
1376
+
1377
+ const useSecret = secret ?? this.secret;
1378
+ if(useSecret==null)
1379
+ throw new Error("Swap secret pre-image not known and not provided, please provide the swap secret pre-image as an argument");
1380
+ if(!this.isValidSecretPreimage(useSecret))
1381
+ throw new Error("Invalid swap secret pre-image provided!");
1034
1382
 
1035
1383
  if(!noCheckExpiry) {
1036
- if(await this.wrapper.contract.isExpired(this._getInitiator(), this.data)) throw new Error("On-chain HTLC already expired!");
1384
+ if(await this.wrapper._contract.isExpired(this._getInitiator(), this._data)) throw new Error("On-chain HTLC already expired!");
1037
1385
  }
1038
- await this.wrapper.messenger.broadcast(new SwapClaimWitnessMessage(this.data, this.secret));
1386
+ await this.wrapper._messenger.broadcast(new SwapClaimWitnessMessage(this._data, useSecret));
1039
1387
  }
1040
1388
 
1389
+ /**
1390
+ * @inheritDoc
1391
+ * @internal
1392
+ */
1041
1393
  async _tick(save?: boolean): Promise<boolean> {
1042
- switch(this.state) {
1394
+ switch(this._state) {
1043
1395
  case FromBTCLNAutoSwapState.PR_CREATED:
1044
1396
  if(this.getQuoteExpiry() < Date.now()) {
1045
- this.state = FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1397
+ this._state = FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED;
1046
1398
  if(save) await this._saveAndEmit();
1047
1399
  return true;
1048
1400
  }
1049
1401
  break;
1050
1402
  case FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED:
1051
1403
  if(this.getDefinitiveExpiryTime() < Date.now()) {
1052
- this.state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1404
+ this._state = FromBTCLNAutoSwapState.QUOTE_EXPIRED;
1053
1405
  if(save) await this._saveAndEmit();
1054
1406
  return true;
1055
1407
  }
1056
1408
  break;
1057
1409
  case FromBTCLNAutoSwapState.PR_PAID:
1058
1410
  case FromBTCLNAutoSwapState.CLAIM_COMMITED:
1059
- const expired = await this.wrapper.contract.isExpired(this._getInitiator(), this.data!);
1411
+ const expired = await this.wrapper._contract.isExpired(this._getInitiator(), this._data!);
1060
1412
  if(expired) {
1061
- this.state = FromBTCLNAutoSwapState.EXPIRED;
1413
+ this._state = FromBTCLNAutoSwapState.EXPIRED;
1062
1414
  if(save) await this._saveAndEmit();
1063
1415
  return true;
1064
1416
  }
1065
- if(this.state===FromBTCLNAutoSwapState.CLAIM_COMMITED) {
1417
+ if(this._state===FromBTCLNAutoSwapState.CLAIM_COMMITED) {
1066
1418
  //Broadcast the secret over the provided messenger channel
1067
- if(this.broadcastTickCounter===0) await this._broadcastSecret(true).catch(e => {
1419
+ if(this.broadcastTickCounter===0 && this.secret!=null) await this._broadcastSecret(true).catch(e => {
1068
1420
  this.logger.warn("_tick(): Error when broadcasting swap secret: ", e);
1069
1421
  });
1070
1422
  this.broadcastTickCounter = (this.broadcastTickCounter + 1) % 3; //Broadcast every 3rd tick
@@ -1075,4 +1427,16 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
1075
1427
  return false;
1076
1428
  }
1077
1429
 
1430
+ /**
1431
+ * Forcibly sets the swap secret pre-image from on-chain data
1432
+ *
1433
+ * @internal
1434
+ */
1435
+ _setSwapSecret(secret: string) {
1436
+ this.secret = secret;
1437
+ if(this.pr==null) {
1438
+ this.pr = Buffer.from(sha256(Buffer.from(secret, "hex"))).toString("hex");
1439
+ }
1440
+ }
1441
+
1078
1442
  }