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