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