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