@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
|
@@ -38,24 +38,75 @@ import {
|
|
|
38
38
|
serializePriceInfoType
|
|
39
39
|
} from "../../types/PriceInfoType";
|
|
40
40
|
import {toBitcoinWallet} from "../../utils/BitcoinWalletUtils";
|
|
41
|
+
import {SwapExecutionActionBitcoin} from "../../types/SwapExecutionAction";
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
|
-
* State enum for SPV
|
|
44
|
-
* @category Swaps
|
|
44
|
+
* State enum for SPV vault (UTXO-controlled vault) based swaps
|
|
45
|
+
* @category Swaps/Bitcoin → Smart chain
|
|
45
46
|
*/
|
|
46
47
|
export enum SpvFromBTCSwapState {
|
|
48
|
+
/**
|
|
49
|
+
* Catastrophic failure has occurred when processing the swap on the smart chain side,
|
|
50
|
+
* this implies a bug in the smart contract code or the user and intermediary deliberately
|
|
51
|
+
* creating a bitcoin transaction with invalid format unparsable by the smart contract.
|
|
52
|
+
*/
|
|
47
53
|
CLOSED = -5,
|
|
48
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Some of the bitcoin swap transaction inputs were double-spent, this means the swap
|
|
56
|
+
* has failed and no BTC was sent
|
|
57
|
+
*/
|
|
58
|
+
FAILED = -4,
|
|
59
|
+
/**
|
|
60
|
+
* The intermediary (LP) declined to co-sign the submitted PSBT, hence the swap failed
|
|
61
|
+
*/
|
|
49
62
|
DECLINED = -3,
|
|
63
|
+
/**
|
|
64
|
+
* Swap has expired for good and there is no way how it can be executed anymore
|
|
65
|
+
*/
|
|
50
66
|
QUOTE_EXPIRED = -2,
|
|
67
|
+
/**
|
|
68
|
+
* A swap is almost expired, and it should be presented to the user as expired, though
|
|
69
|
+
* there is still a chance that it will be processed
|
|
70
|
+
*/
|
|
51
71
|
QUOTE_SOFT_EXPIRED = -1,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Swap was created, use the {@link SpvFromBTCSwap.getFundedPsbt} or {@link SpvFromBTCSwap.getPsbt} functions
|
|
74
|
+
* to get the bitcoin swap PSBT that should be signed by the user's wallet and then submitted via the
|
|
75
|
+
* {@link SpvFromBTCSwap.submitPsbt} function.
|
|
76
|
+
*/
|
|
77
|
+
CREATED = 0,
|
|
78
|
+
/**
|
|
79
|
+
* Swap bitcoin PSBT was submitted by the client to the SDK
|
|
80
|
+
*/
|
|
81
|
+
SIGNED = 1,
|
|
82
|
+
/**
|
|
83
|
+
* Swap bitcoin PSBT sent to the intermediary (LP), waiting for the intermediary co-sign
|
|
84
|
+
* it and broadcast. You can use the {@link SpvFromBTCSwap.waitTillClaimedOrFronted}
|
|
85
|
+
* function to wait till the intermediary broadcasts the transaction and the transaction
|
|
86
|
+
* confirms.
|
|
87
|
+
*/
|
|
88
|
+
POSTED = 2,
|
|
89
|
+
/**
|
|
90
|
+
* Intermediary (LP) has co-signed and broadcasted the bitcoin transaction. You can use the
|
|
91
|
+
* {@link SpvFromBTCSwap.waitTillClaimedOrFronted} function to wait till the transaction
|
|
92
|
+
* confirms.
|
|
93
|
+
*/
|
|
94
|
+
BROADCASTED = 3,
|
|
95
|
+
/**
|
|
96
|
+
* Settlement on the destination smart chain was fronted and funds were already received
|
|
97
|
+
* by the user, even before the final settlement.
|
|
98
|
+
*/
|
|
99
|
+
FRONTED = 4,
|
|
100
|
+
/**
|
|
101
|
+
* Bitcoin transaction confirmed with necessary amount of confirmations, wait for automatic
|
|
102
|
+
* settlement by the watchtower with the {@link waitTillClaimedOrFronted} function, or settle manually
|
|
103
|
+
* using the {@link FromBTCSwap.claim} or {@link FromBTCSwap.txsClaim} function.
|
|
104
|
+
*/
|
|
105
|
+
BTC_TX_CONFIRMED = 5,
|
|
106
|
+
/**
|
|
107
|
+
* Swap settled on the smart chain and funds received
|
|
108
|
+
*/
|
|
109
|
+
CLAIMED = 6
|
|
59
110
|
}
|
|
60
111
|
|
|
61
112
|
export type SpvFromBTCSwapInit = ISwapInit & {
|
|
@@ -116,52 +167,80 @@ export function isSpvFromBTCSwapInit(obj: any): obj is SpvFromBTCSwapInit {
|
|
|
116
167
|
isISwapInit(obj);
|
|
117
168
|
}
|
|
118
169
|
|
|
170
|
+
/**
|
|
171
|
+
* New spv vault (UTXO-controlled vault) based swaps for Bitcoin -> Smart chain swaps not requiring
|
|
172
|
+
* any initiation on the destination chain, and with the added possibility for the user to receive
|
|
173
|
+
* a native token on the destination chain as part of the swap (a "gas drop" feature).
|
|
174
|
+
*
|
|
175
|
+
* @category Swaps/Bitcoin → Smart chain
|
|
176
|
+
*/
|
|
119
177
|
export class SpvFromBTCSwap<T extends ChainType>
|
|
120
178
|
extends ISwap<T, SpvFromBTCTypeDefinition<T>>
|
|
121
179
|
implements IBTCWalletSwap, ISwapWithGasDrop<T>, IClaimableSwap<T, SpvFromBTCTypeDefinition<T>, SpvFromBTCSwapState> {
|
|
122
180
|
|
|
123
|
-
readonly TYPE = SwapType.SPV_VAULT_FROM_BTC;
|
|
181
|
+
readonly TYPE: SwapType.SPV_VAULT_FROM_BTC = SwapType.SPV_VAULT_FROM_BTC;
|
|
182
|
+
/**
|
|
183
|
+
* @inheritDoc
|
|
184
|
+
* @internal
|
|
185
|
+
*/
|
|
124
186
|
protected readonly logger: LoggerType;
|
|
125
187
|
|
|
126
|
-
readonly quoteId: string;
|
|
127
|
-
readonly recipient: string;
|
|
188
|
+
private readonly quoteId: string;
|
|
189
|
+
private readonly recipient: string;
|
|
128
190
|
|
|
129
|
-
readonly vaultOwner: string;
|
|
130
|
-
readonly vaultId: bigint;
|
|
131
|
-
readonly vaultRequiredConfirmations: number;
|
|
132
|
-
readonly vaultTokenMultipliers: bigint[];
|
|
191
|
+
private readonly vaultOwner: string;
|
|
192
|
+
private readonly vaultId: bigint;
|
|
193
|
+
private readonly vaultRequiredConfirmations: number;
|
|
194
|
+
private readonly vaultTokenMultipliers: bigint[];
|
|
133
195
|
|
|
134
|
-
readonly vaultBtcAddress: string;
|
|
135
|
-
readonly vaultUtxo: string;
|
|
136
|
-
readonly vaultUtxoValue: bigint;
|
|
196
|
+
private readonly vaultBtcAddress: string;
|
|
197
|
+
private readonly vaultUtxo: string;
|
|
198
|
+
private readonly vaultUtxoValue: bigint;
|
|
137
199
|
|
|
138
|
-
readonly btcDestinationAddress: string;
|
|
139
|
-
readonly btcAmount: bigint;
|
|
140
|
-
readonly btcAmountSwap: bigint;
|
|
141
|
-
readonly btcAmountGas: bigint;
|
|
142
|
-
readonly minimumBtcFeeRate: number;
|
|
143
|
-
|
|
144
|
-
readonly outputTotalSwap: bigint;
|
|
145
|
-
readonly outputSwapToken: string;
|
|
146
|
-
readonly outputTotalGas: bigint;
|
|
147
|
-
readonly outputGasToken: string;
|
|
200
|
+
private readonly btcDestinationAddress: string;
|
|
201
|
+
private readonly btcAmount: bigint;
|
|
202
|
+
private readonly btcAmountSwap: bigint;
|
|
203
|
+
private readonly btcAmountGas: bigint;
|
|
148
204
|
|
|
149
|
-
readonly
|
|
150
|
-
readonly
|
|
205
|
+
private readonly outputTotalSwap: bigint;
|
|
206
|
+
private readonly outputSwapToken: string;
|
|
207
|
+
private readonly outputTotalGas: bigint;
|
|
208
|
+
private readonly outputGasToken: string;
|
|
151
209
|
|
|
152
|
-
readonly
|
|
153
|
-
readonly
|
|
154
|
-
readonly executionFeeShare: bigint;
|
|
210
|
+
private readonly gasSwapFeeBtc: bigint;
|
|
211
|
+
private readonly gasSwapFee: bigint;
|
|
155
212
|
|
|
156
|
-
readonly
|
|
213
|
+
private readonly callerFeeShare: bigint;
|
|
214
|
+
private readonly frontingFeeShare: bigint;
|
|
215
|
+
private readonly executionFeeShare: bigint;
|
|
157
216
|
|
|
158
|
-
gasPricingInfo?: PriceInfoType;
|
|
217
|
+
private readonly gasPricingInfo?: PriceInfoType;
|
|
159
218
|
|
|
160
|
-
|
|
219
|
+
/**
|
|
220
|
+
* @internal
|
|
221
|
+
*/
|
|
222
|
+
readonly _genesisSmartChainBlockHeight: number;
|
|
223
|
+
/**
|
|
224
|
+
* @internal
|
|
225
|
+
*/
|
|
226
|
+
_senderAddress?: string;
|
|
227
|
+
/**
|
|
228
|
+
* @internal
|
|
229
|
+
*/
|
|
230
|
+
_claimTxId?: string;
|
|
231
|
+
/**
|
|
232
|
+
* @internal
|
|
233
|
+
*/
|
|
234
|
+
_frontTxId?: string;
|
|
235
|
+
/**
|
|
236
|
+
* @internal
|
|
237
|
+
*/
|
|
238
|
+
_data?: T["SpvVaultWithdrawalData"];
|
|
161
239
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
240
|
+
/**
|
|
241
|
+
* Minimum fee rate in sats/vB that the input bitcoin transaction needs to pay
|
|
242
|
+
*/
|
|
243
|
+
readonly minimumBtcFeeRate: number;
|
|
165
244
|
|
|
166
245
|
constructor(wrapper: SpvFromBTCWrapper<T>, init: SpvFromBTCSwapInit);
|
|
167
246
|
constructor(wrapper: SpvFromBTCWrapper<T>, obj: any);
|
|
@@ -169,7 +248,7 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
169
248
|
if(isSpvFromBTCSwapInit(initOrObject) && initOrObject.url!=null) initOrObject.url += "/frombtc_spv";
|
|
170
249
|
super(wrapper, initOrObject);
|
|
171
250
|
if(isSpvFromBTCSwapInit(initOrObject)) {
|
|
172
|
-
this.
|
|
251
|
+
this._state = SpvFromBTCSwapState.CREATED;
|
|
173
252
|
this.quoteId = initOrObject.quoteId;
|
|
174
253
|
this.recipient = initOrObject.recipient;
|
|
175
254
|
this.vaultOwner = initOrObject.vaultOwner;
|
|
@@ -193,9 +272,9 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
193
272
|
this.callerFeeShare = initOrObject.callerFeeShare;
|
|
194
273
|
this.frontingFeeShare = initOrObject.frontingFeeShare;
|
|
195
274
|
this.executionFeeShare = initOrObject.executionFeeShare;
|
|
196
|
-
this.
|
|
275
|
+
this._genesisSmartChainBlockHeight = initOrObject.genesisSmartChainBlockHeight;
|
|
197
276
|
this.gasPricingInfo = initOrObject.gasPricingInfo;
|
|
198
|
-
const vaultAddressType = toCoinselectAddressType(toOutputScript(this.wrapper.
|
|
277
|
+
const vaultAddressType = toCoinselectAddressType(toOutputScript(this.wrapper._options.bitcoinNetwork, this.vaultBtcAddress));
|
|
199
278
|
if(vaultAddressType!=="p2tr" && vaultAddressType!=="p2wpkh" && vaultAddressType!=="p2wsh")
|
|
200
279
|
throw new Error("Vault address type must be of witness type: p2tr, p2wpkh, p2wsh");
|
|
201
280
|
} else {
|
|
@@ -222,22 +301,26 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
222
301
|
this.callerFeeShare = BigInt(initOrObject.callerFeeShare);
|
|
223
302
|
this.frontingFeeShare = BigInt(initOrObject.frontingFeeShare);
|
|
224
303
|
this.executionFeeShare = BigInt(initOrObject.executionFeeShare);
|
|
225
|
-
this.
|
|
226
|
-
this.
|
|
227
|
-
this.
|
|
228
|
-
this.
|
|
304
|
+
this._genesisSmartChainBlockHeight = initOrObject.genesisSmartChainBlockHeight;
|
|
305
|
+
this._senderAddress = initOrObject.senderAddress;
|
|
306
|
+
this._claimTxId = initOrObject.claimTxId;
|
|
307
|
+
this._frontTxId = initOrObject.frontTxId;
|
|
229
308
|
this.gasPricingInfo = deserializePriceInfoType(initOrObject.gasPricingInfo);
|
|
230
|
-
if(initOrObject.data!=null) this.
|
|
309
|
+
if(initOrObject.data!=null) this._data = new this.wrapper._spvWithdrawalDataDeserializer(initOrObject.data);
|
|
231
310
|
}
|
|
232
311
|
this.tryCalculateSwapFee();
|
|
233
312
|
this.logger = getLogger("SPVFromBTC("+this.getId()+"): ");
|
|
234
313
|
}
|
|
235
314
|
|
|
315
|
+
/**
|
|
316
|
+
* @inheritDoc
|
|
317
|
+
* @internal
|
|
318
|
+
*/
|
|
236
319
|
protected upgradeVersion() { /*NOOP*/ }
|
|
237
320
|
|
|
238
321
|
/**
|
|
239
|
-
*
|
|
240
|
-
* @
|
|
322
|
+
* @inheritDoc
|
|
323
|
+
* @internal
|
|
241
324
|
*/
|
|
242
325
|
protected tryCalculateSwapFee() {
|
|
243
326
|
if(this.swapFeeBtc==null && this.swapFee!=null) {
|
|
@@ -246,7 +329,7 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
246
329
|
|
|
247
330
|
if(this.pricingInfo!=null && this.pricingInfo.swapPriceUSatPerToken==null) {
|
|
248
331
|
const priceUsdPerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
|
|
249
|
-
this.pricingInfo = this.wrapper.
|
|
332
|
+
this.pricingInfo = this.wrapper._prices.recomputePriceInfoReceive(
|
|
250
333
|
this.chainIdentifier,
|
|
251
334
|
this.btcAmountSwap,
|
|
252
335
|
this.pricingInfo.satsBaseFee,
|
|
@@ -262,10 +345,13 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
262
345
|
//////////////////////////////
|
|
263
346
|
//// Pricing
|
|
264
347
|
|
|
348
|
+
/**
|
|
349
|
+
* @inheritDoc
|
|
350
|
+
*/
|
|
265
351
|
async refreshPriceData(): Promise<void> {
|
|
266
352
|
if(this.pricingInfo==null) return;
|
|
267
353
|
const usdPricePerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
|
|
268
|
-
this.pricingInfo = await this.wrapper.
|
|
354
|
+
this.pricingInfo = await this.wrapper._prices.isValidAmountReceive(
|
|
269
355
|
this.chainIdentifier,
|
|
270
356
|
this.btcAmountSwap,
|
|
271
357
|
this.pricingInfo.satsBaseFee,
|
|
@@ -280,97 +366,198 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
280
366
|
//////////////////////////////
|
|
281
367
|
//// Getters & utils
|
|
282
368
|
|
|
369
|
+
/**
|
|
370
|
+
* @inheritDoc
|
|
371
|
+
* @internal
|
|
372
|
+
*/
|
|
283
373
|
_getInitiator(): string {
|
|
284
374
|
return this.recipient;
|
|
285
375
|
}
|
|
286
376
|
|
|
377
|
+
/**
|
|
378
|
+
* @inheritDoc
|
|
379
|
+
* @internal
|
|
380
|
+
*/
|
|
287
381
|
_getEscrowHash(): string | null {
|
|
288
|
-
return this.
|
|
382
|
+
return this._data?.btcTx?.txid ?? null;
|
|
289
383
|
}
|
|
290
384
|
|
|
385
|
+
/**
|
|
386
|
+
* @inheritDoc
|
|
387
|
+
*/
|
|
291
388
|
getId(): string {
|
|
292
|
-
return this.quoteId+this.
|
|
389
|
+
return this.quoteId+this._randomNonce;
|
|
293
390
|
}
|
|
294
391
|
|
|
392
|
+
/**
|
|
393
|
+
* @inheritDoc
|
|
394
|
+
*/
|
|
295
395
|
getQuoteExpiry(): number {
|
|
296
396
|
return this.expiry - 20*1000;
|
|
297
397
|
}
|
|
298
398
|
|
|
299
|
-
|
|
300
|
-
|
|
399
|
+
/**
|
|
400
|
+
* @inheritDoc
|
|
401
|
+
* @internal
|
|
402
|
+
*/
|
|
403
|
+
_verifyQuoteDefinitelyExpired(): Promise<boolean> {
|
|
404
|
+
return Promise.resolve(this.expiry<Date.now());
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* @inheritDoc
|
|
409
|
+
* @internal
|
|
410
|
+
*/
|
|
411
|
+
_verifyQuoteValid(): Promise<boolean> {
|
|
412
|
+
return Promise.resolve(this.expiry>Date.now() && (this._state===SpvFromBTCSwapState.CREATED || this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED));
|
|
301
413
|
}
|
|
302
414
|
|
|
415
|
+
/**
|
|
416
|
+
* @inheritDoc
|
|
417
|
+
*/
|
|
303
418
|
getOutputAddress(): string | null {
|
|
304
419
|
return this.recipient;
|
|
305
420
|
}
|
|
306
421
|
|
|
422
|
+
/**
|
|
423
|
+
* @inheritDoc
|
|
424
|
+
*/
|
|
307
425
|
getOutputTxId(): string | null {
|
|
308
|
-
return this.
|
|
426
|
+
return this._frontTxId ?? this._claimTxId ?? null;
|
|
309
427
|
}
|
|
310
428
|
|
|
429
|
+
/**
|
|
430
|
+
* @inheritDoc
|
|
431
|
+
*/
|
|
311
432
|
getInputAddress(): string | null {
|
|
312
|
-
return this.
|
|
433
|
+
return this._senderAddress ?? null;
|
|
313
434
|
}
|
|
314
435
|
|
|
436
|
+
/**
|
|
437
|
+
* @inheritDoc
|
|
438
|
+
*/
|
|
315
439
|
getInputTxId(): string | null {
|
|
316
|
-
return this.
|
|
440
|
+
return this._data?.btcTx?.txid ?? null;
|
|
317
441
|
}
|
|
318
442
|
|
|
443
|
+
/**
|
|
444
|
+
* @inheritDoc
|
|
445
|
+
*/
|
|
319
446
|
requiresAction(): boolean {
|
|
320
|
-
return this.
|
|
447
|
+
return this._state===SpvFromBTCSwapState.BTC_TX_CONFIRMED;
|
|
321
448
|
}
|
|
322
449
|
|
|
450
|
+
/**
|
|
451
|
+
* @inheritDoc
|
|
452
|
+
*/
|
|
323
453
|
isFinished(): boolean {
|
|
324
|
-
return this.
|
|
454
|
+
return this._state===SpvFromBTCSwapState.CLAIMED || this._state===SpvFromBTCSwapState.QUOTE_EXPIRED || this._state===SpvFromBTCSwapState.FAILED;
|
|
325
455
|
}
|
|
326
456
|
|
|
457
|
+
/**
|
|
458
|
+
* @inheritDoc
|
|
459
|
+
*/
|
|
327
460
|
isClaimable(): boolean {
|
|
328
|
-
return this.
|
|
461
|
+
return this._state===SpvFromBTCSwapState.BTC_TX_CONFIRMED;
|
|
329
462
|
}
|
|
330
463
|
|
|
464
|
+
/**
|
|
465
|
+
* @inheritDoc
|
|
466
|
+
*/
|
|
331
467
|
isSuccessful(): boolean {
|
|
332
|
-
return this.
|
|
468
|
+
return this._state===SpvFromBTCSwapState.FRONTED || this._state===SpvFromBTCSwapState.CLAIMED;
|
|
333
469
|
}
|
|
334
470
|
|
|
471
|
+
/**
|
|
472
|
+
* @inheritDoc
|
|
473
|
+
*/
|
|
335
474
|
isFailed(): boolean {
|
|
336
|
-
return this.
|
|
475
|
+
return this._state===SpvFromBTCSwapState.FAILED || this._state===SpvFromBTCSwapState.DECLINED || this._state===SpvFromBTCSwapState.CLOSED;
|
|
337
476
|
}
|
|
338
477
|
|
|
478
|
+
/**
|
|
479
|
+
* @inheritDoc
|
|
480
|
+
*/
|
|
339
481
|
isQuoteExpired(): boolean {
|
|
340
|
-
return this.
|
|
482
|
+
return this._state===SpvFromBTCSwapState.QUOTE_EXPIRED;
|
|
341
483
|
}
|
|
342
484
|
|
|
485
|
+
/**
|
|
486
|
+
* @inheritDoc
|
|
487
|
+
*/
|
|
343
488
|
isQuoteSoftExpired(): boolean {
|
|
344
|
-
return this.
|
|
489
|
+
return this._state===SpvFromBTCSwapState.QUOTE_EXPIRED || this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Returns the data about used spv vault (UTXO-controlled vault) to perform the swap
|
|
494
|
+
*/
|
|
495
|
+
getSpvVaultData(): {
|
|
496
|
+
owner: string,
|
|
497
|
+
vaultId: bigint,
|
|
498
|
+
utxo: string
|
|
499
|
+
} {
|
|
500
|
+
return {
|
|
501
|
+
owner: this.vaultOwner,
|
|
502
|
+
vaultId: this.vaultId,
|
|
503
|
+
utxo: this.vaultUtxo
|
|
504
|
+
}
|
|
345
505
|
}
|
|
346
506
|
|
|
347
507
|
|
|
348
508
|
//////////////////////////////
|
|
349
509
|
//// Amounts & fees
|
|
350
510
|
|
|
511
|
+
/**
|
|
512
|
+
* Returns the input BTC amount in sats without any fees
|
|
513
|
+
*
|
|
514
|
+
* @internal
|
|
515
|
+
*/
|
|
351
516
|
protected getInputSwapAmountWithoutFee(): bigint {
|
|
352
517
|
return (this.btcAmountSwap - this.swapFeeBtc) * 100_000n / (100_000n + this.callerFeeShare + this.frontingFeeShare + this.executionFeeShare);
|
|
353
518
|
}
|
|
354
519
|
|
|
520
|
+
/**
|
|
521
|
+
* Returns the input gas BTC amount in sats without any fees
|
|
522
|
+
*
|
|
523
|
+
* @internal
|
|
524
|
+
*/
|
|
355
525
|
protected getInputGasAmountWithoutFee(): bigint {
|
|
356
526
|
return (this.btcAmountGas - this.gasSwapFeeBtc) * 100_000n / (100_000n + this.callerFeeShare + this.frontingFeeShare);
|
|
357
527
|
}
|
|
358
528
|
|
|
529
|
+
/**
|
|
530
|
+
* Returns to total input BTC amount in sats without any fees (this is BTC amount for the swap + BTC amount
|
|
531
|
+
* for the gas drop).
|
|
532
|
+
*
|
|
533
|
+
* @internal
|
|
534
|
+
*/
|
|
359
535
|
protected getInputAmountWithoutFee(): bigint {
|
|
360
536
|
return this.getInputSwapAmountWithoutFee() + this.getInputGasAmountWithoutFee();
|
|
361
537
|
}
|
|
362
538
|
|
|
539
|
+
/**
|
|
540
|
+
* Returns the swap output amount without any fees, this value is therefore always higher than
|
|
541
|
+
* the actual received output.
|
|
542
|
+
*
|
|
543
|
+
* @internal
|
|
544
|
+
*/
|
|
363
545
|
protected getOutputWithoutFee(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
|
|
364
546
|
return toTokenAmount(
|
|
365
547
|
(this.outputTotalSwap * (100_000n + this.callerFeeShare + this.frontingFeeShare + this.executionFeeShare) / 100_000n) + (this.swapFee ?? 0n),
|
|
366
|
-
this.wrapper.
|
|
548
|
+
this.wrapper._tokens[this.outputSwapToken], this.wrapper._prices, this.pricingInfo
|
|
367
549
|
);
|
|
368
550
|
}
|
|
369
551
|
|
|
552
|
+
/**
|
|
553
|
+
* Returns the swap fee charged by the intermediary (LP) on this swap
|
|
554
|
+
*
|
|
555
|
+
* @internal
|
|
556
|
+
*/
|
|
370
557
|
protected getSwapFee(): Fee<T["ChainId"], BtcToken<false>, SCToken<T["ChainId"]>> {
|
|
371
558
|
if(this.pricingInfo==null) throw new Error("No pricing info known, cannot estimate fee!");
|
|
372
559
|
|
|
373
|
-
const outputToken = this.wrapper.
|
|
560
|
+
const outputToken = this.wrapper._tokens[this.outputSwapToken];
|
|
374
561
|
const gasSwapFeeInOutputToken = this.gasSwapFeeBtc
|
|
375
562
|
* (10n ** BigInt(outputToken.decimals))
|
|
376
563
|
* 1_000_000n
|
|
@@ -380,38 +567,44 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
380
567
|
const swapFeePPM = feeWithoutBaseFee * 1000000n / (this.btcAmount - this.swapFeeBtc - this.gasSwapFeeBtc);
|
|
381
568
|
|
|
382
569
|
const amountInSrcToken = toTokenAmount(
|
|
383
|
-
this.swapFeeBtc + this.gasSwapFeeBtc, BitcoinTokens.BTC, this.wrapper.
|
|
570
|
+
this.swapFeeBtc + this.gasSwapFeeBtc, BitcoinTokens.BTC, this.wrapper._prices, this.pricingInfo
|
|
384
571
|
);
|
|
385
572
|
return {
|
|
386
573
|
amountInSrcToken,
|
|
387
|
-
amountInDstToken: toTokenAmount(this.swapFee + gasSwapFeeInOutputToken, outputToken, this.wrapper.
|
|
574
|
+
amountInDstToken: toTokenAmount(this.swapFee + gasSwapFeeInOutputToken, outputToken, this.wrapper._prices, this.pricingInfo),
|
|
388
575
|
currentUsdValue: amountInSrcToken.currentUsdValue,
|
|
389
576
|
usdValue: amountInSrcToken.usdValue,
|
|
390
577
|
pastUsdValue: amountInSrcToken.pastUsdValue,
|
|
391
578
|
composition: {
|
|
392
|
-
base: toTokenAmount(this.pricingInfo.satsBaseFee, BitcoinTokens.BTC, this.wrapper.
|
|
579
|
+
base: toTokenAmount(this.pricingInfo.satsBaseFee, BitcoinTokens.BTC, this.wrapper._prices, this.pricingInfo),
|
|
393
580
|
percentage: ppmToPercentage(swapFeePPM)
|
|
394
581
|
}
|
|
395
582
|
};
|
|
396
583
|
}
|
|
397
584
|
|
|
585
|
+
/**
|
|
586
|
+
* Returns the fee to be paid to watchtowers on the destination chain to automatically
|
|
587
|
+
* process and settle this swap without requiring any user interaction
|
|
588
|
+
*
|
|
589
|
+
* @internal
|
|
590
|
+
*/
|
|
398
591
|
protected getWatchtowerFee(): Fee<T["ChainId"], BtcToken<false>, SCToken<T["ChainId"]>> {
|
|
399
592
|
if(this.pricingInfo==null) throw new Error("No pricing info known, cannot estimate fee!");
|
|
400
593
|
|
|
401
594
|
const totalFeeShare = this.callerFeeShare + this.frontingFeeShare;
|
|
402
|
-
const outputToken = this.wrapper.
|
|
595
|
+
const outputToken = this.wrapper._tokens[this.outputSwapToken];
|
|
403
596
|
const watchtowerFeeInOutputToken = this.getInputGasAmountWithoutFee() * totalFeeShare
|
|
404
597
|
* (10n ** BigInt(outputToken.decimals))
|
|
405
598
|
* 1_000_000n
|
|
406
599
|
/ this.pricingInfo.swapPriceUSatPerToken
|
|
407
600
|
/ 100_000n;
|
|
408
601
|
const feeBtc = this.getInputAmountWithoutFee() * (totalFeeShare + this.executionFeeShare) / 100_000n;
|
|
409
|
-
const amountInSrcToken = toTokenAmount(feeBtc, BitcoinTokens.BTC, this.wrapper.
|
|
602
|
+
const amountInSrcToken = toTokenAmount(feeBtc, BitcoinTokens.BTC, this.wrapper._prices, this.pricingInfo);
|
|
410
603
|
return {
|
|
411
604
|
amountInSrcToken,
|
|
412
605
|
amountInDstToken: toTokenAmount(
|
|
413
606
|
(this.outputTotalSwap * (totalFeeShare + this.executionFeeShare) / 100_000n) + watchtowerFeeInOutputToken,
|
|
414
|
-
outputToken, this.wrapper.
|
|
607
|
+
outputToken, this.wrapper._prices, this.pricingInfo
|
|
415
608
|
),
|
|
416
609
|
currentUsdValue: amountInSrcToken.currentUsdValue,
|
|
417
610
|
usdValue: amountInSrcToken.usdValue,
|
|
@@ -419,19 +612,22 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
419
612
|
};
|
|
420
613
|
}
|
|
421
614
|
|
|
615
|
+
/**
|
|
616
|
+
* @inheritDoc
|
|
617
|
+
*/
|
|
422
618
|
getFee(): Fee<T["ChainId"], BtcToken<false>, SCToken<T["ChainId"]>> {
|
|
423
619
|
const swapFee = this.getSwapFee();
|
|
424
620
|
const watchtowerFee = this.getWatchtowerFee();
|
|
425
621
|
|
|
426
622
|
const amountInSrcToken = toTokenAmount(
|
|
427
623
|
swapFee.amountInSrcToken.rawAmount + watchtowerFee.amountInSrcToken.rawAmount,
|
|
428
|
-
BitcoinTokens.BTC, this.wrapper.
|
|
624
|
+
BitcoinTokens.BTC, this.wrapper._prices, this.pricingInfo
|
|
429
625
|
);
|
|
430
626
|
return {
|
|
431
627
|
amountInSrcToken,
|
|
432
628
|
amountInDstToken: toTokenAmount(
|
|
433
629
|
swapFee.amountInDstToken.rawAmount + watchtowerFee.amountInDstToken.rawAmount,
|
|
434
|
-
this.wrapper.
|
|
630
|
+
this.wrapper._tokens[this.outputSwapToken], this.wrapper._prices, this.pricingInfo
|
|
435
631
|
),
|
|
436
632
|
currentUsdValue: amountInSrcToken.currentUsdValue,
|
|
437
633
|
usdValue: amountInSrcToken.usdValue,
|
|
@@ -439,6 +635,9 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
439
635
|
};
|
|
440
636
|
}
|
|
441
637
|
|
|
638
|
+
/**
|
|
639
|
+
* @inheritDoc
|
|
640
|
+
*/
|
|
442
641
|
getFeeBreakdown(): [
|
|
443
642
|
{type: FeeType.SWAP, fee: Fee<T["ChainId"], BtcToken<false>, SCToken<T["ChainId"]>>},
|
|
444
643
|
{type: FeeType.NETWORK_OUTPUT, fee: Fee<T["ChainId"], BtcToken<false>, SCToken<T["ChainId"]>>}
|
|
@@ -455,38 +654,63 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
455
654
|
];
|
|
456
655
|
}
|
|
457
656
|
|
|
657
|
+
/**
|
|
658
|
+
* @inheritDoc
|
|
659
|
+
*/
|
|
458
660
|
getOutputToken(): SCToken<T["ChainId"]> {
|
|
459
|
-
return this.wrapper.
|
|
661
|
+
return this.wrapper._tokens[this.outputSwapToken];
|
|
460
662
|
}
|
|
461
663
|
|
|
664
|
+
/**
|
|
665
|
+
* @inheritDoc
|
|
666
|
+
*/
|
|
462
667
|
getOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
|
|
463
|
-
return toTokenAmount(this.outputTotalSwap, this.wrapper.
|
|
668
|
+
return toTokenAmount(this.outputTotalSwap, this.wrapper._tokens[this.outputSwapToken], this.wrapper._prices, this.pricingInfo);
|
|
464
669
|
}
|
|
465
670
|
|
|
671
|
+
/**
|
|
672
|
+
* @inheritDoc
|
|
673
|
+
*/
|
|
466
674
|
getGasDropOutput(): TokenAmount<T["ChainId"], SCToken<T["ChainId"]>, true> {
|
|
467
|
-
return toTokenAmount(this.outputTotalGas, this.wrapper.
|
|
675
|
+
return toTokenAmount(this.outputTotalGas, this.wrapper._tokens[this.outputGasToken], this.wrapper._prices, this.gasPricingInfo);
|
|
468
676
|
}
|
|
469
677
|
|
|
678
|
+
/**
|
|
679
|
+
* @inheritDoc
|
|
680
|
+
*/
|
|
470
681
|
getInputWithoutFee(): TokenAmount<T["ChainId"], BtcToken<false>, true> {
|
|
471
|
-
return toTokenAmount(this.getInputAmountWithoutFee(), BitcoinTokens.BTC, this.wrapper.
|
|
682
|
+
return toTokenAmount(this.getInputAmountWithoutFee(), BitcoinTokens.BTC, this.wrapper._prices, this.pricingInfo);
|
|
472
683
|
}
|
|
473
684
|
|
|
685
|
+
/**
|
|
686
|
+
* @inheritDoc
|
|
687
|
+
*/
|
|
474
688
|
getInputToken(): BtcToken<false> {
|
|
475
689
|
return BitcoinTokens.BTC;
|
|
476
690
|
}
|
|
477
691
|
|
|
692
|
+
/**
|
|
693
|
+
* @inheritDoc
|
|
694
|
+
*/
|
|
478
695
|
getInput(): TokenAmount<T["ChainId"], BtcToken<false>, true> {
|
|
479
|
-
return toTokenAmount(this.btcAmount, BitcoinTokens.BTC, this.wrapper.
|
|
696
|
+
return toTokenAmount(this.btcAmount, BitcoinTokens.BTC, this.wrapper._prices, this.pricingInfo);
|
|
480
697
|
}
|
|
481
698
|
|
|
482
699
|
|
|
483
700
|
//////////////////////////////
|
|
484
701
|
//// Bitcoin tx
|
|
485
702
|
|
|
703
|
+
/**
|
|
704
|
+
* @inheritDoc
|
|
705
|
+
*/
|
|
486
706
|
getRequiredConfirmationsCount(): number {
|
|
487
707
|
return this.vaultRequiredConfirmations;
|
|
488
708
|
}
|
|
489
709
|
|
|
710
|
+
/**
|
|
711
|
+
* Returns raw transaction details that can be used to manually create a swap PSBT. It is better to use
|
|
712
|
+
* the {@link getPsbt} or {@link getFundedPsbt} function retrieve an already prepared PSBT.
|
|
713
|
+
*/
|
|
490
714
|
async getTransactionDetails(): Promise<{
|
|
491
715
|
in0txid: string,
|
|
492
716
|
in0vout: number,
|
|
@@ -501,11 +725,11 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
501
725
|
}> {
|
|
502
726
|
const [txId, voutStr] = this.vaultUtxo.split(":");
|
|
503
727
|
|
|
504
|
-
const vaultScript = toOutputScript(this.wrapper.
|
|
728
|
+
const vaultScript = toOutputScript(this.wrapper._options.bitcoinNetwork, this.vaultBtcAddress);
|
|
505
729
|
|
|
506
|
-
const out2script = toOutputScript(this.wrapper.
|
|
730
|
+
const out2script = toOutputScript(this.wrapper._options.bitcoinNetwork, this.btcDestinationAddress);
|
|
507
731
|
|
|
508
|
-
const opReturnData = this.wrapper.
|
|
732
|
+
const opReturnData = this.wrapper._contract.toOpReturnData(
|
|
509
733
|
this.recipient,
|
|
510
734
|
[
|
|
511
735
|
this.outputTotalSwap / this.vaultTokenMultipliers[0],
|
|
@@ -539,9 +763,9 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
539
763
|
}
|
|
540
764
|
|
|
541
765
|
/**
|
|
542
|
-
* Returns the raw PSBT (not funded), the wallet should fund the PSBT (add its inputs)
|
|
543
|
-
* 2nd input (input 1 - indexing from 0) to the value returned in `in1sequence`, sign the PSBT and then pass
|
|
544
|
-
* it back to the
|
|
766
|
+
* Returns the raw PSBT (not funded), the wallet should fund the PSBT (add its inputs) and importantly **set the nSequence field of the
|
|
767
|
+
* 2nd input** (input 1 - indexing from 0) to the value returned in `in1sequence`, sign the PSBT and then pass
|
|
768
|
+
* it back to the swap with {@link submitPsbt} function.
|
|
545
769
|
*/
|
|
546
770
|
async getPsbt(): Promise<{
|
|
547
771
|
psbt: Transaction,
|
|
@@ -588,10 +812,13 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
588
812
|
/**
|
|
589
813
|
* Returns the PSBT that is already funded with wallet's UTXOs (runs a coin-selection algorithm to choose UTXOs to use),
|
|
590
814
|
* also returns inputs indices that need to be signed by the wallet before submitting the PSBT back to the SDK with
|
|
591
|
-
*
|
|
815
|
+
* {@link submitPsbt}
|
|
816
|
+
*
|
|
817
|
+
* @remarks
|
|
818
|
+
* Note that when passing the `feeRate` argument, the fee must be at least {@link minimumBtcFeeRate} sats/vB.
|
|
592
819
|
*
|
|
593
820
|
* @param _bitcoinWallet Sender's bitcoin wallet
|
|
594
|
-
* @param feeRate Optional fee rate for the transaction
|
|
821
|
+
* @param feeRate Optional fee rate in sats/vB for the transaction
|
|
595
822
|
* @param additionalOutputs additional outputs to add to the PSBT - can be used to collect fees from users
|
|
596
823
|
*/
|
|
597
824
|
async getFundedPsbt(
|
|
@@ -604,7 +831,7 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
604
831
|
psbtBase64: string,
|
|
605
832
|
signInputs: number[]
|
|
606
833
|
}> {
|
|
607
|
-
const bitcoinWallet: IBitcoinWallet = toBitcoinWallet(_bitcoinWallet, this.wrapper.
|
|
834
|
+
const bitcoinWallet: IBitcoinWallet = toBitcoinWallet(_bitcoinWallet, this.wrapper._btcRpc, this.wrapper._options.bitcoinNetwork);
|
|
608
835
|
if(feeRate!=null) {
|
|
609
836
|
if(feeRate<this.minimumBtcFeeRate) throw new Error("Bitcoin tx fee needs to be at least "+this.minimumBtcFeeRate+" sats/vB");
|
|
610
837
|
} else {
|
|
@@ -614,7 +841,7 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
614
841
|
if(additionalOutputs!=null) additionalOutputs.forEach(output => {
|
|
615
842
|
psbt.addOutput({
|
|
616
843
|
amount: output.amount,
|
|
617
|
-
script: (output as {outputScript: Uint8Array}).outputScript ?? toOutputScript(this.wrapper.
|
|
844
|
+
script: (output as {outputScript: Uint8Array}).outputScript ?? toOutputScript(this.wrapper._options.bitcoinNetwork, (output as {address: string}).address)
|
|
618
845
|
});
|
|
619
846
|
});
|
|
620
847
|
psbt = await bitcoinWallet.fundPsbt(psbt, feeRate);
|
|
@@ -634,9 +861,7 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
634
861
|
}
|
|
635
862
|
|
|
636
863
|
/**
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
* @param _psbt A psbt - either a Transaction object or a hex or base64 encoded PSBT string
|
|
864
|
+
* @inheritDoc
|
|
640
865
|
*/
|
|
641
866
|
async submitPsbt(_psbt: Transaction | string): Promise<string> {
|
|
642
867
|
const psbt = parsePsbtTransaction(_psbt);
|
|
@@ -647,7 +872,7 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
647
872
|
}
|
|
648
873
|
|
|
649
874
|
//Ensure valid state
|
|
650
|
-
if(this.
|
|
875
|
+
if(this._state!==SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED && this._state!==SpvFromBTCSwapState.CREATED) {
|
|
651
876
|
throw new Error("Invalid swap state!");
|
|
652
877
|
}
|
|
653
878
|
if(this.url==null) throw new Error("LP URL not known, cannot submit PSBT!");
|
|
@@ -658,8 +883,8 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
658
883
|
throw new Error("Legacy (non-segwit) inputs are not allowed in the transaction!");
|
|
659
884
|
psbt.finalizeIdx(i);
|
|
660
885
|
}
|
|
661
|
-
const btcTx = await this.wrapper.
|
|
662
|
-
const data = await this.wrapper.
|
|
886
|
+
const btcTx = await this.wrapper._btcRpc.parseTransaction(Buffer.from(psbt.toBytes(true)).toString("hex"));
|
|
887
|
+
const data = await this.wrapper._contract.getWithdrawalData(btcTx);
|
|
663
888
|
|
|
664
889
|
this.logger.debug("submitPsbt(): parsed withdrawal data: ", data);
|
|
665
890
|
|
|
@@ -673,7 +898,7 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
673
898
|
data.executionFeeRate!==this.executionFeeShare ||
|
|
674
899
|
data.getSpentVaultUtxo()!==this.vaultUtxo ||
|
|
675
900
|
BigInt(data.getNewVaultBtcAmount())!==this.vaultUtxoValue ||
|
|
676
|
-
!data.getNewVaultScript().equals(toOutputScript(this.wrapper.
|
|
901
|
+
!data.getNewVaultScript().equals(toOutputScript(this.wrapper._options.bitcoinNetwork, this.vaultBtcAddress)) ||
|
|
677
902
|
data.getExecutionData()!=null
|
|
678
903
|
) {
|
|
679
904
|
throw new Error("Invalid withdrawal tx data submitted!");
|
|
@@ -684,19 +909,19 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
684
909
|
if(
|
|
685
910
|
lpOutput.script==null ||
|
|
686
911
|
lpOutput.amount!==this.btcAmount ||
|
|
687
|
-
!toOutputScript(this.wrapper.
|
|
912
|
+
!toOutputScript(this.wrapper._options.bitcoinNetwork, this.btcDestinationAddress).equals(Buffer.from(lpOutput.script))
|
|
688
913
|
) {
|
|
689
914
|
throw new Error("Invalid LP bitcoin output in transaction!");
|
|
690
915
|
}
|
|
691
916
|
|
|
692
917
|
//Verify vault utxo not spent yet
|
|
693
|
-
if(await this.wrapper.
|
|
918
|
+
if(await this.wrapper._btcRpc.isSpent(this.vaultUtxo)) {
|
|
694
919
|
throw new Error("Vault UTXO already spent, please create new swap!");
|
|
695
920
|
}
|
|
696
921
|
|
|
697
922
|
//Verify tx is parsable by the contract
|
|
698
923
|
try {
|
|
699
|
-
await this.wrapper.
|
|
924
|
+
await this.wrapper._contract.checkWithdrawalTx(data);
|
|
700
925
|
} catch (e: any) {
|
|
701
926
|
throw new Error("Transaction not parsable by the contract: "+(e.message ?? e.toString()));
|
|
702
927
|
}
|
|
@@ -706,7 +931,7 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
706
931
|
throw new Error("Quote expired!");
|
|
707
932
|
}
|
|
708
933
|
|
|
709
|
-
this.
|
|
934
|
+
this._data = data;
|
|
710
935
|
this.initiated = true;
|
|
711
936
|
await this._saveAndEmit(SpvFromBTCSwapState.SIGNED);
|
|
712
937
|
|
|
@@ -725,16 +950,22 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
725
950
|
throw e;
|
|
726
951
|
}
|
|
727
952
|
|
|
728
|
-
return this.
|
|
953
|
+
return this._data.getTxId();
|
|
729
954
|
}
|
|
730
955
|
|
|
956
|
+
/**
|
|
957
|
+
* @inheritDoc
|
|
958
|
+
*/
|
|
731
959
|
async estimateBitcoinFee(_bitcoinWallet: IBitcoinWallet | MinimalBitcoinWalletInterface, feeRate?: number): Promise<TokenAmount<any, BtcToken<false>, true> | null> {
|
|
732
|
-
const bitcoinWallet: IBitcoinWallet = toBitcoinWallet(_bitcoinWallet, this.wrapper.
|
|
960
|
+
const bitcoinWallet: IBitcoinWallet = toBitcoinWallet(_bitcoinWallet, this.wrapper._btcRpc, this.wrapper._options.bitcoinNetwork);
|
|
733
961
|
const txFee = await bitcoinWallet.getFundedPsbtFee((await this.getPsbt()).psbt, feeRate);
|
|
734
962
|
if(txFee==null) return null;
|
|
735
|
-
return toTokenAmount(BigInt(txFee), BitcoinTokens.BTC, this.wrapper.
|
|
963
|
+
return toTokenAmount(BigInt(txFee), BitcoinTokens.BTC, this.wrapper._prices, this.pricingInfo);
|
|
736
964
|
}
|
|
737
965
|
|
|
966
|
+
/**
|
|
967
|
+
* @inheritDoc
|
|
968
|
+
*/
|
|
738
969
|
async sendBitcoinTransaction(wallet: IBitcoinWallet | MinimalBitcoinWalletInterfaceWithSigner, feeRate?: number): Promise<string> {
|
|
739
970
|
const {psbt, psbtBase64, psbtHex, signInputs} = await this.getFundedPsbt(wallet, feeRate);
|
|
740
971
|
let signedPsbt: Transaction | string;
|
|
@@ -749,14 +980,15 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
749
980
|
}
|
|
750
981
|
|
|
751
982
|
/**
|
|
752
|
-
* Executes the swap with the provided bitcoin wallet
|
|
983
|
+
* Executes the swap with the provided bitcoin wallet
|
|
753
984
|
*
|
|
754
985
|
* @param wallet Bitcoin wallet to use to sign the bitcoin transaction
|
|
755
986
|
* @param callbacks Callbacks to track the progress of the swap
|
|
756
987
|
* @param options Optional options for the swap like feeRate, AbortSignal, and timeouts/intervals
|
|
757
988
|
*
|
|
758
989
|
* @returns {boolean} Whether a swap was settled automatically by swap watchtowers or requires manual claim by the
|
|
759
|
-
* user, in case `false` is returned the user should call
|
|
990
|
+
* user, in case `false` is returned the user should call the {@link claim} function to settle the swap on the
|
|
991
|
+
* destination manually
|
|
760
992
|
*/
|
|
761
993
|
async execute(
|
|
762
994
|
wallet: IBitcoinWallet | MinimalBitcoinWalletInterfaceWithSigner,
|
|
@@ -773,23 +1005,23 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
773
1005
|
maxWaitTillAutomaticSettlementSeconds?: number
|
|
774
1006
|
}
|
|
775
1007
|
): Promise<boolean> {
|
|
776
|
-
if(this.
|
|
777
|
-
if(this.
|
|
778
|
-
if(this.
|
|
779
|
-
if(this.
|
|
780
|
-
if(this.
|
|
1008
|
+
if(this._state===SpvFromBTCSwapState.CLOSED) throw new Error("Swap encountered a catastrophic failure!");
|
|
1009
|
+
if(this._state===SpvFromBTCSwapState.FAILED) throw new Error("Swap failed!");
|
|
1010
|
+
if(this._state===SpvFromBTCSwapState.DECLINED) throw new Error("Swap execution already declined by the LP!");
|
|
1011
|
+
if(this._state===SpvFromBTCSwapState.QUOTE_EXPIRED) throw new Error("Swap quote expired!");
|
|
1012
|
+
if(this._state===SpvFromBTCSwapState.CLAIMED || this._state===SpvFromBTCSwapState.FRONTED) throw new Error("Swap already settled or fronted!");
|
|
781
1013
|
|
|
782
|
-
if(this.
|
|
1014
|
+
if(this._state===SpvFromBTCSwapState.CREATED) {
|
|
783
1015
|
const txId = await this.sendBitcoinTransaction(wallet, options?.feeRate);
|
|
784
1016
|
if(callbacks?.onSourceTransactionSent!=null) callbacks.onSourceTransactionSent(txId);
|
|
785
1017
|
}
|
|
786
|
-
if(this.
|
|
1018
|
+
if(this._state===SpvFromBTCSwapState.POSTED || this._state===SpvFromBTCSwapState.BROADCASTED) {
|
|
787
1019
|
const txId = await this.waitForBitcoinTransaction(callbacks?.onSourceTransactionConfirmationStatus, options?.btcTxCheckIntervalSeconds, options?.abortSignal);
|
|
788
1020
|
if (callbacks?.onSourceTransactionConfirmed != null) callbacks.onSourceTransactionConfirmed(txId);
|
|
789
1021
|
}
|
|
790
1022
|
// @ts-ignore
|
|
791
|
-
if(this.
|
|
792
|
-
if(this.
|
|
1023
|
+
if(this._state===SpvFromBTCSwapState.CLAIMED || this._state===SpvFromBTCSwapState.FRONTED) return true;
|
|
1024
|
+
if(this._state===SpvFromBTCSwapState.BTC_TX_CONFIRMED) {
|
|
793
1025
|
const success = await this.waitTillClaimedOrFronted(options?.maxWaitTillAutomaticSettlementSeconds ?? 60, options?.abortSignal);
|
|
794
1026
|
if(success && callbacks?.onSwapSettled!=null) callbacks.onSwapSettled(this.getOutputTxId()!);
|
|
795
1027
|
return success;
|
|
@@ -798,14 +1030,24 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
798
1030
|
throw new Error("Unexpected state reached!");
|
|
799
1031
|
}
|
|
800
1032
|
|
|
1033
|
+
/**
|
|
1034
|
+
* @inheritDoc
|
|
1035
|
+
*
|
|
1036
|
+
* @param options.bitcoinWallet Optional bitcoin wallet address specification to return a funded PSBT,
|
|
1037
|
+
* if not provided a raw PSBT is returned instead which necessitates the implementor to manually add
|
|
1038
|
+
* inputs to the bitcoin transaction and **set the nSequence field of the 2nd input** (input 1 -
|
|
1039
|
+
* indexing from 0) to the value returned in `in1sequence`
|
|
1040
|
+
*/
|
|
801
1041
|
async txsExecute(options?: {
|
|
802
1042
|
bitcoinWallet?: MinimalBitcoinWalletInterface,
|
|
803
|
-
})
|
|
804
|
-
|
|
805
|
-
|
|
1043
|
+
}): Promise<[
|
|
1044
|
+
SwapExecutionActionBitcoin<"RAW_PSBT" | "FUNDED_PSBT">
|
|
1045
|
+
]> {
|
|
1046
|
+
if(this._state===SpvFromBTCSwapState.CREATED) {
|
|
1047
|
+
if (!await this._verifyQuoteValid()) throw new Error("Quote already expired or close to expiry!");
|
|
806
1048
|
return [
|
|
807
1049
|
{
|
|
808
|
-
name: "Payment"
|
|
1050
|
+
name: "Payment",
|
|
809
1051
|
description: "Send funds to the bitcoin swap address",
|
|
810
1052
|
chain: "BITCOIN",
|
|
811
1053
|
txs: [
|
|
@@ -826,6 +1068,7 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
826
1068
|
|
|
827
1069
|
/**
|
|
828
1070
|
* Checks whether a bitcoin payment was already made, returns the payment or null when no payment has been made.
|
|
1071
|
+
* @internal
|
|
829
1072
|
*/
|
|
830
1073
|
protected async getBitcoinPayment(): Promise<{
|
|
831
1074
|
txId: string,
|
|
@@ -833,9 +1076,9 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
833
1076
|
targetConfirmations: number,
|
|
834
1077
|
inputAddresses?: string[]
|
|
835
1078
|
} | null> {
|
|
836
|
-
if(this.
|
|
1079
|
+
if(this._data?.btcTx?.txid==null) return null;
|
|
837
1080
|
|
|
838
|
-
const result = await this.wrapper.
|
|
1081
|
+
const result = await this.wrapper._btcRpc.getTransaction(this._data?.btcTx?.txid);
|
|
839
1082
|
if(result==null) return null;
|
|
840
1083
|
|
|
841
1084
|
return {
|
|
@@ -847,12 +1090,10 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
847
1090
|
}
|
|
848
1091
|
|
|
849
1092
|
/**
|
|
850
|
-
*
|
|
1093
|
+
* @inheritDoc
|
|
851
1094
|
*
|
|
852
|
-
* @
|
|
853
|
-
*
|
|
854
|
-
* @param abortSignal Abort signal
|
|
855
|
-
* @throws {Error} if in invalid state (must be CLAIM_COMMITED)
|
|
1095
|
+
* @throws {Error} if in invalid state (must be {@link SpvFromBTCSwapState.POSTED} or
|
|
1096
|
+
* {@link SpvFromBTCSwapState.BROADCASTED} states)
|
|
856
1097
|
*/
|
|
857
1098
|
async waitForBitcoinTransaction(
|
|
858
1099
|
updateCallback?: (txId?: string, confirmations?: number, targetConfirmations?: number, txEtaMs?: number) => void,
|
|
@@ -860,25 +1101,25 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
860
1101
|
abortSignal?: AbortSignal
|
|
861
1102
|
): Promise<string> {
|
|
862
1103
|
if(
|
|
863
|
-
this.
|
|
864
|
-
this.
|
|
865
|
-
!(this.
|
|
1104
|
+
this._state!==SpvFromBTCSwapState.POSTED &&
|
|
1105
|
+
this._state!==SpvFromBTCSwapState.BROADCASTED &&
|
|
1106
|
+
!(this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED && this.initiated)
|
|
866
1107
|
) throw new Error("Must be in POSTED or BROADCASTED state!");
|
|
867
|
-
if(this.
|
|
1108
|
+
if(this._data==null) throw new Error("Expected swap to have withdrawal data filled!");
|
|
868
1109
|
|
|
869
|
-
const result = await this.wrapper.
|
|
870
|
-
this.
|
|
1110
|
+
const result = await this.wrapper._btcRpc.waitForTransaction(
|
|
1111
|
+
this._data.btcTx.txid,
|
|
871
1112
|
this.vaultRequiredConfirmations,
|
|
872
1113
|
(btcTx?: BtcTxWithBlockheight, txEtaMs?: number) => {
|
|
873
1114
|
if(updateCallback!=null) updateCallback(btcTx?.txid, btcTx?.confirmations, this.vaultRequiredConfirmations, txEtaMs);
|
|
874
1115
|
if(btcTx==null) return;
|
|
875
1116
|
let save = false;
|
|
876
|
-
if(btcTx.inputAddresses!=null && this.
|
|
877
|
-
this.
|
|
1117
|
+
if(btcTx.inputAddresses!=null && this._senderAddress==null) {
|
|
1118
|
+
this._senderAddress = btcTx.inputAddresses[1];
|
|
878
1119
|
save = true;
|
|
879
1120
|
}
|
|
880
|
-
if(this.
|
|
881
|
-
this.
|
|
1121
|
+
if(this._state===SpvFromBTCSwapState.POSTED || this._state==SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED) {
|
|
1122
|
+
this._state = SpvFromBTCSwapState.BROADCASTED;
|
|
882
1123
|
save = true;
|
|
883
1124
|
}
|
|
884
1125
|
if(save) this._saveAndEmit();
|
|
@@ -890,15 +1131,15 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
890
1131
|
if(abortSignal!=null) abortSignal.throwIfAborted();
|
|
891
1132
|
|
|
892
1133
|
let save = false;
|
|
893
|
-
if(result.inputAddresses!=null && this.
|
|
894
|
-
this.
|
|
1134
|
+
if(result.inputAddresses!=null && this._senderAddress==null) {
|
|
1135
|
+
this._senderAddress = result.inputAddresses[1];
|
|
895
1136
|
save = true;
|
|
896
1137
|
}
|
|
897
1138
|
if(
|
|
898
|
-
(this.
|
|
899
|
-
(this.
|
|
1139
|
+
(this._state as SpvFromBTCSwapState)!==SpvFromBTCSwapState.FRONTED &&
|
|
1140
|
+
(this._state as SpvFromBTCSwapState)!==SpvFromBTCSwapState.CLAIMED
|
|
900
1141
|
) {
|
|
901
|
-
this.
|
|
1142
|
+
this._state = SpvFromBTCSwapState.BTC_TX_CONFIRMED;
|
|
902
1143
|
save = true;
|
|
903
1144
|
}
|
|
904
1145
|
if(save) await this._saveAndEmit();
|
|
@@ -911,10 +1152,16 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
911
1152
|
//// Claim
|
|
912
1153
|
|
|
913
1154
|
/**
|
|
914
|
-
* Returns transactions
|
|
915
|
-
*
|
|
1155
|
+
* Returns transactions for settling (claiming) the swap if the swap requires manual settlement, you can check so
|
|
1156
|
+
* with isClaimable. After sending the transaction manually be sure to call the waitTillClaimed function to wait
|
|
1157
|
+
* till the claim transaction is observed, processed by the SDK and state of the swap properly updated.
|
|
916
1158
|
*
|
|
917
|
-
* @
|
|
1159
|
+
* @remarks
|
|
1160
|
+
* Might also return transactions necessary to sync the bitcoin light client.
|
|
1161
|
+
*
|
|
1162
|
+
* @param _signer Address of the signer to create the claim transactions for, can also be different to the recipient
|
|
1163
|
+
*
|
|
1164
|
+
* @throws {Error} If the swap is in invalid state (must be {@link SpvFromBTCSwapState.BTC_TX_CONFIRMED})
|
|
918
1165
|
*/
|
|
919
1166
|
async txsClaim(_signer?: string | T["Signer"] | T["NativeSigner"]): Promise<T["TX"][]> {
|
|
920
1167
|
let address: string | undefined = undefined;
|
|
@@ -924,77 +1171,90 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
924
1171
|
} else if (isAbstractSigner(_signer)) {
|
|
925
1172
|
address = _signer.getAddress();
|
|
926
1173
|
} else {
|
|
927
|
-
address = (await this.wrapper.
|
|
1174
|
+
address = (await this.wrapper._chain.wrapSigner(_signer)).getAddress();
|
|
928
1175
|
}
|
|
929
1176
|
}
|
|
930
1177
|
|
|
931
1178
|
if(!this.isClaimable()) throw new Error("Must be in BTC_TX_CONFIRMED state!");
|
|
932
|
-
if(this.
|
|
1179
|
+
if(this._data==null) throw new Error("Expected swap to have withdrawal data filled!");
|
|
933
1180
|
|
|
934
|
-
const vaultData = await this.wrapper.
|
|
1181
|
+
const vaultData = await this.wrapper._contract.getVaultData(this.vaultOwner, this.vaultId);
|
|
935
1182
|
if(vaultData==null) throw new Error(`Vault data for ${this.vaultOwner}:${this.vaultId.toString(10)} not found (already closed???)!`);
|
|
936
1183
|
|
|
937
|
-
const btcTx = await this.wrapper.
|
|
938
|
-
if(btcTx==null) throw new Error(`Bitcoin transaction ${this.
|
|
1184
|
+
const btcTx = await this.wrapper._btcRpc.getTransaction(this._data.btcTx.txid);
|
|
1185
|
+
if(btcTx==null) throw new Error(`Bitcoin transaction ${this._data.btcTx.txid} not found!`);
|
|
939
1186
|
const txs = [btcTx];
|
|
940
1187
|
|
|
941
1188
|
//Trace back from current tx to the vaultData-specified UTXO
|
|
942
1189
|
const vaultUtxo = vaultData.getUtxo();
|
|
943
1190
|
while(txs[0].ins[0].txid+":"+txs[0].ins[0].vout!==vaultUtxo) {
|
|
944
|
-
const btcTx = await this.wrapper.
|
|
945
|
-
if(btcTx==null) throw new Error(`Prior withdrawal bitcoin transaction ${this.
|
|
1191
|
+
const btcTx = await this.wrapper._btcRpc.getTransaction(txs[0].ins[0].txid);
|
|
1192
|
+
if(btcTx==null) throw new Error(`Prior withdrawal bitcoin transaction ${this._data.btcTx.txid} not found!`);
|
|
946
1193
|
txs.unshift(btcTx);
|
|
947
1194
|
}
|
|
948
1195
|
|
|
949
1196
|
//Parse transactions to withdrawal data
|
|
950
1197
|
const withdrawalData: T["SpvVaultWithdrawalData"][] = [];
|
|
951
1198
|
for(let tx of txs) {
|
|
952
|
-
withdrawalData.push(await this.wrapper.
|
|
1199
|
+
withdrawalData.push(await this.wrapper._contract.getWithdrawalData(tx));
|
|
953
1200
|
}
|
|
954
1201
|
|
|
955
|
-
return await this.wrapper.
|
|
1202
|
+
return await this.wrapper._contract.txsClaim(
|
|
956
1203
|
address ?? this._getInitiator(), vaultData,
|
|
957
1204
|
withdrawalData.map(tx => {return {tx}}),
|
|
958
|
-
this.wrapper.
|
|
1205
|
+
this.wrapper._synchronizer, true
|
|
959
1206
|
);
|
|
960
1207
|
}
|
|
961
1208
|
|
|
962
1209
|
/**
|
|
963
|
-
*
|
|
1210
|
+
* Settles the swap by claiming the funds on the destination chain if the swap requires manual settlement, you can
|
|
1211
|
+
* check so with isClaimable.
|
|
1212
|
+
*
|
|
1213
|
+
* @remarks
|
|
1214
|
+
* Might also sync the bitcoin light client during the process.
|
|
1215
|
+
*
|
|
1216
|
+
* @param _signer Signer to use for signing the settlement transactions, can also be different to the recipient
|
|
1217
|
+
* @param abortSignal Abort signal
|
|
1218
|
+
* @param onBeforeTxSent Optional callback triggered before the claim transaction is broadcasted
|
|
964
1219
|
*
|
|
965
|
-
* @
|
|
966
|
-
* @param abortSignal Abort signal to stop waiting for transaction confirmation
|
|
1220
|
+
* @throws {Error} If the swap is in invalid state (must be {@link SpvFromBTCSwapState.BTC_TX_CONFIRMED})
|
|
967
1221
|
*/
|
|
968
|
-
async claim(_signer: T["Signer"] | T["NativeSigner"], abortSignal?: AbortSignal): Promise<string> {
|
|
969
|
-
const signer = isAbstractSigner(_signer) ? _signer : await this.wrapper.
|
|
1222
|
+
async claim(_signer: T["Signer"] | T["NativeSigner"], abortSignal?: AbortSignal, onBeforeTxSent?: (txId: string) => void): Promise<string> {
|
|
1223
|
+
const signer = isAbstractSigner(_signer) ? _signer : await this.wrapper._chain.wrapSigner(_signer);
|
|
970
1224
|
let txIds: string[];
|
|
971
1225
|
try {
|
|
972
|
-
|
|
973
|
-
|
|
1226
|
+
let txCount = 0;
|
|
1227
|
+
const txs = await this.txsClaim(signer);
|
|
1228
|
+
txIds = await this.wrapper._chain.sendAndConfirm(
|
|
1229
|
+
signer, txs, true, abortSignal, undefined, (txId: string) => {
|
|
1230
|
+
txCount++;
|
|
1231
|
+
if(onBeforeTxSent!=null && txCount===txs.length) onBeforeTxSent(txId);
|
|
1232
|
+
return Promise.resolve();
|
|
1233
|
+
}
|
|
974
1234
|
);
|
|
975
1235
|
} catch (e) {
|
|
976
|
-
if(this.
|
|
1236
|
+
if(this._data==null) throw e;
|
|
977
1237
|
|
|
978
1238
|
this.logger.info("claim(): Failed to claim ourselves, checking swap claim state...");
|
|
979
|
-
if(this.
|
|
1239
|
+
if(this._state===SpvFromBTCSwapState.CLAIMED) {
|
|
980
1240
|
this.logger.info("claim(): Transaction state is CLAIMED, swap was successfully claimed by the watchtower");
|
|
981
|
-
return this.
|
|
1241
|
+
return this._claimTxId!;
|
|
982
1242
|
}
|
|
983
|
-
const withdrawalState = await this.wrapper.
|
|
1243
|
+
const withdrawalState = await this.wrapper._contract.getWithdrawalState(this._data, this._genesisSmartChainBlockHeight);
|
|
984
1244
|
if(withdrawalState!=null && withdrawalState.type===SpvWithdrawalStateType.CLAIMED) {
|
|
985
1245
|
this.logger.info("claim(): Transaction status is CLAIMED, swap was successfully claimed by the watchtower");
|
|
986
|
-
this.
|
|
1246
|
+
this._claimTxId = withdrawalState.txId;
|
|
987
1247
|
await this._saveAndEmit(SpvFromBTCSwapState.CLAIMED);
|
|
988
1248
|
return withdrawalState.txId;
|
|
989
1249
|
}
|
|
990
1250
|
throw e;
|
|
991
1251
|
}
|
|
992
1252
|
|
|
993
|
-
this.
|
|
1253
|
+
this._claimTxId = txIds[0];
|
|
994
1254
|
if(
|
|
995
|
-
this.
|
|
996
|
-
this.
|
|
997
|
-
this.
|
|
1255
|
+
this._state===SpvFromBTCSwapState.POSTED || this._state===SpvFromBTCSwapState.BROADCASTED ||
|
|
1256
|
+
this._state===SpvFromBTCSwapState.BTC_TX_CONFIRMED || this._state===SpvFromBTCSwapState.FAILED ||
|
|
1257
|
+
this._state===SpvFromBTCSwapState.FRONTED
|
|
998
1258
|
) {
|
|
999
1259
|
await this._saveAndEmit(SpvFromBTCSwapState.CLAIMED);
|
|
1000
1260
|
}
|
|
@@ -1006,12 +1266,12 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1006
1266
|
*
|
|
1007
1267
|
* @param abortSignal
|
|
1008
1268
|
* @param interval How often to check (in seconds), default to 5s
|
|
1009
|
-
* @
|
|
1269
|
+
* @internal
|
|
1010
1270
|
*/
|
|
1011
1271
|
protected async watchdogWaitTillResult(abortSignal?: AbortSignal, interval: number = 5): Promise<
|
|
1012
1272
|
SpvWithdrawalClaimedState | SpvWithdrawalFrontedState | SpvWithdrawalClosedState
|
|
1013
1273
|
> {
|
|
1014
|
-
if(this.
|
|
1274
|
+
if(this._data==null) throw new Error("Cannot await the result before the btc transaction is sent!");
|
|
1015
1275
|
|
|
1016
1276
|
let status: SpvWithdrawalState = {type: SpvWithdrawalStateType.NOT_FOUND};
|
|
1017
1277
|
while(status.type===SpvWithdrawalStateType.NOT_FOUND) {
|
|
@@ -1019,8 +1279,8 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1019
1279
|
try {
|
|
1020
1280
|
//Be smart about checking withdrawal state
|
|
1021
1281
|
if(await this._shouldCheckWithdrawalState()) {
|
|
1022
|
-
status = await this.wrapper.
|
|
1023
|
-
this.
|
|
1282
|
+
status = await this.wrapper._contract.getWithdrawalState(
|
|
1283
|
+
this._data, this._genesisSmartChainBlockHeight
|
|
1024
1284
|
) ?? {type: SpvWithdrawalStateType.NOT_FOUND};
|
|
1025
1285
|
}
|
|
1026
1286
|
} catch (e) {
|
|
@@ -1032,17 +1292,34 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1032
1292
|
}
|
|
1033
1293
|
|
|
1034
1294
|
/**
|
|
1035
|
-
* Waits till the swap is successfully
|
|
1295
|
+
* Waits till the swap is successfully settled (claimed), should be called after sending the claim (settlement)
|
|
1296
|
+
* transactions manually to wait till the SDK processes the settlement and updates the swap state accordingly.
|
|
1297
|
+
*
|
|
1298
|
+
* @remarks
|
|
1299
|
+
* This is an alias for the {@link waitTillClaimedOrFronted} function and will also resolve if the swap has
|
|
1300
|
+
* been fronted (not necessarily claimed)
|
|
1301
|
+
*
|
|
1302
|
+
* @param maxWaitTimeSeconds – Maximum time in seconds to wait for the swap to be settled
|
|
1303
|
+
* @param abortSignal – AbortSignal
|
|
1304
|
+
*
|
|
1305
|
+
* @returns Whether the swap was claimed in time or not
|
|
1306
|
+
*/
|
|
1307
|
+
waitTillClaimed(maxWaitTimeSeconds?: number, abortSignal?: AbortSignal): Promise<boolean> {
|
|
1308
|
+
return this.waitTillClaimedOrFronted(maxWaitTimeSeconds, abortSignal);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/**
|
|
1312
|
+
* Waits till the swap is successfully fronted or settled on the destination chain
|
|
1313
|
+
*
|
|
1314
|
+
* @param maxWaitTimeSeconds Maximum time in seconds to wait for the swap to be settled (by default
|
|
1315
|
+
* it waits indefinitely)
|
|
1316
|
+
* @param abortSignal Abort signal
|
|
1036
1317
|
*
|
|
1037
|
-
* @param maxWaitTimeSeconds Maximum time in seconds to wait for the swap to be settled
|
|
1038
|
-
* @param abortSignal
|
|
1039
|
-
* @throws {Error} If swap is in invalid state (must be BTC_TX_CONFIRMED)
|
|
1040
|
-
* @throws {Error} If the LP refunded sooner than we were able to claim
|
|
1041
1318
|
* @returns {boolean} whether the swap was claimed or fronted automatically or not, if the swap was not claimed
|
|
1042
|
-
* the user can claim manually through
|
|
1319
|
+
* the user can claim manually through the {@link claim} function
|
|
1043
1320
|
*/
|
|
1044
1321
|
async waitTillClaimedOrFronted(maxWaitTimeSeconds?: number, abortSignal?: AbortSignal): Promise<boolean> {
|
|
1045
|
-
if(this.
|
|
1322
|
+
if(this._state===SpvFromBTCSwapState.CLAIMED || this._state===SpvFromBTCSwapState.FRONTED) return Promise.resolve(true);
|
|
1046
1323
|
|
|
1047
1324
|
const abortController = extendAbortController(abortSignal);
|
|
1048
1325
|
|
|
@@ -1089,24 +1366,24 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1089
1366
|
|
|
1090
1367
|
if(res.type===SpvWithdrawalStateType.FRONTED) {
|
|
1091
1368
|
if(
|
|
1092
|
-
(this.
|
|
1093
|
-
(this.
|
|
1369
|
+
(this._state as SpvFromBTCSwapState)!==SpvFromBTCSwapState.FRONTED ||
|
|
1370
|
+
(this._state as SpvFromBTCSwapState)!==SpvFromBTCSwapState.CLAIMED
|
|
1094
1371
|
) {
|
|
1095
|
-
this.
|
|
1372
|
+
this._frontTxId = res.txId;
|
|
1096
1373
|
await this._saveAndEmit(SpvFromBTCSwapState.FRONTED);
|
|
1097
1374
|
}
|
|
1098
1375
|
}
|
|
1099
1376
|
if(res.type===SpvWithdrawalStateType.CLAIMED) {
|
|
1100
1377
|
if(
|
|
1101
|
-
(this.
|
|
1378
|
+
(this._state as SpvFromBTCSwapState)!==SpvFromBTCSwapState.CLAIMED
|
|
1102
1379
|
) {
|
|
1103
|
-
this.
|
|
1380
|
+
this._claimTxId = res.txId;
|
|
1104
1381
|
await this._saveAndEmit(SpvFromBTCSwapState.FRONTED);
|
|
1105
1382
|
}
|
|
1106
1383
|
}
|
|
1107
1384
|
if(res.type===SpvWithdrawalStateType.CLOSED) {
|
|
1108
1385
|
if(
|
|
1109
|
-
(this.
|
|
1386
|
+
(this._state as SpvFromBTCSwapState)!==SpvFromBTCSwapState.CLOSED
|
|
1110
1387
|
) await this._saveAndEmit(SpvFromBTCSwapState.CLOSED);
|
|
1111
1388
|
throw new Error("Swap failed with catastrophic error!");
|
|
1112
1389
|
}
|
|
@@ -1115,12 +1392,14 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1115
1392
|
}
|
|
1116
1393
|
|
|
1117
1394
|
/**
|
|
1118
|
-
* Waits till the bitcoin transaction confirms and swap
|
|
1395
|
+
* Waits till the bitcoin transaction confirms and swap settled on the destination chain
|
|
1119
1396
|
*
|
|
1120
|
-
* @param abortSignal Abort signal
|
|
1121
|
-
* @param checkIntervalSeconds How often to check the bitcoin transaction
|
|
1122
1397
|
* @param updateCallback Callback called when txId is found, and also called with subsequent confirmations
|
|
1123
|
-
* @
|
|
1398
|
+
* @param checkIntervalSeconds How often to check the bitcoin transaction (5 seconds by default)
|
|
1399
|
+
* @param abortSignal Abort signal
|
|
1400
|
+
*
|
|
1401
|
+
* @throws {Error} if in invalid state (must be {@link SpvFromBTCSwapState.POSTED} or
|
|
1402
|
+
* {@link SpvFromBTCSwapState.BROADCASTED} states)
|
|
1124
1403
|
*/
|
|
1125
1404
|
async waitTillExecuted(
|
|
1126
1405
|
updateCallback?: (txId?: string, confirmations?: number, targetConfirmations?: number, txEtaMs?: number) => void,
|
|
@@ -1135,6 +1414,9 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1135
1414
|
//////////////////////////////
|
|
1136
1415
|
//// Storage
|
|
1137
1416
|
|
|
1417
|
+
/**
|
|
1418
|
+
* @inheritDoc
|
|
1419
|
+
*/
|
|
1138
1420
|
serialize(): any {
|
|
1139
1421
|
return {
|
|
1140
1422
|
...super.serialize(),
|
|
@@ -1161,13 +1443,13 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1161
1443
|
callerFeeShare: this.callerFeeShare.toString(10),
|
|
1162
1444
|
frontingFeeShare: this.frontingFeeShare.toString(10),
|
|
1163
1445
|
executionFeeShare: this.executionFeeShare.toString(10),
|
|
1164
|
-
genesisSmartChainBlockHeight: this.
|
|
1446
|
+
genesisSmartChainBlockHeight: this._genesisSmartChainBlockHeight,
|
|
1165
1447
|
gasPricingInfo: serializePriceInfoType(this.gasPricingInfo),
|
|
1166
1448
|
|
|
1167
|
-
senderAddress: this.
|
|
1168
|
-
claimTxId: this.
|
|
1169
|
-
frontTxId: this.
|
|
1170
|
-
data: this.
|
|
1449
|
+
senderAddress: this._senderAddress,
|
|
1450
|
+
claimTxId: this._claimTxId,
|
|
1451
|
+
frontTxId: this._frontTxId,
|
|
1452
|
+
data: this._data?.serialize()
|
|
1171
1453
|
};
|
|
1172
1454
|
}
|
|
1173
1455
|
|
|
@@ -1176,41 +1458,45 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1176
1458
|
//// Swap ticks & sync
|
|
1177
1459
|
|
|
1178
1460
|
/**
|
|
1179
|
-
*
|
|
1461
|
+
* Used to set the txId of the bitcoin payment from the on-chain events listener
|
|
1180
1462
|
*
|
|
1181
1463
|
* @param txId
|
|
1464
|
+
* @internal
|
|
1182
1465
|
*/
|
|
1183
1466
|
async _setBitcoinTxId(txId: string) {
|
|
1184
|
-
if(this.
|
|
1185
|
-
if(txId!=this.
|
|
1467
|
+
if(this._data==null) return;
|
|
1468
|
+
if(txId!=this._data.btcTx.txid) return;
|
|
1186
1469
|
|
|
1187
|
-
if(this.
|
|
1188
|
-
const btcTx = await this.wrapper.
|
|
1470
|
+
if(this._senderAddress!=null) return;
|
|
1471
|
+
const btcTx = await this.wrapper._btcRpc.getTransaction(txId);
|
|
1189
1472
|
if(btcTx==null || btcTx.inputAddresses==null) return;
|
|
1190
1473
|
|
|
1191
|
-
this.
|
|
1474
|
+
this._senderAddress = btcTx.inputAddresses[1];
|
|
1192
1475
|
}
|
|
1193
1476
|
|
|
1477
|
+
/**
|
|
1478
|
+
* @internal
|
|
1479
|
+
*/
|
|
1194
1480
|
async _syncStateFromBitcoin(save?: boolean) {
|
|
1195
|
-
if(this.
|
|
1481
|
+
if(this._data?.btcTx==null) return false;
|
|
1196
1482
|
|
|
1197
1483
|
//Check if bitcoin payment was confirmed
|
|
1198
1484
|
const res = await this.getBitcoinPayment();
|
|
1199
1485
|
if(res==null) {
|
|
1200
1486
|
//Check inputs double-spent
|
|
1201
|
-
for(let input of this.
|
|
1202
|
-
if(await this.wrapper.
|
|
1487
|
+
for(let input of this._data.btcTx.ins) {
|
|
1488
|
+
if(await this.wrapper._btcRpc.isSpent(input.txid+":"+input.vout, true)) {
|
|
1203
1489
|
if(
|
|
1204
|
-
this.
|
|
1205
|
-
this.
|
|
1206
|
-
this.
|
|
1207
|
-
this.
|
|
1490
|
+
this._state===SpvFromBTCSwapState.SIGNED ||
|
|
1491
|
+
this._state===SpvFromBTCSwapState.POSTED ||
|
|
1492
|
+
this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED ||
|
|
1493
|
+
this._state===SpvFromBTCSwapState.DECLINED
|
|
1208
1494
|
) {
|
|
1209
1495
|
//One of the inputs was double-spent
|
|
1210
|
-
this.
|
|
1496
|
+
this._state = SpvFromBTCSwapState.QUOTE_EXPIRED;
|
|
1211
1497
|
} else {
|
|
1212
1498
|
//One of the inputs was double-spent
|
|
1213
|
-
this.
|
|
1499
|
+
this._state = SpvFromBTCSwapState.FAILED;
|
|
1214
1500
|
}
|
|
1215
1501
|
if(save) await this._saveAndEmit();
|
|
1216
1502
|
return true;
|
|
@@ -1218,26 +1504,26 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1218
1504
|
}
|
|
1219
1505
|
} else {
|
|
1220
1506
|
let needsSave = false;
|
|
1221
|
-
if(res.inputAddresses!=null && this.
|
|
1222
|
-
this.
|
|
1507
|
+
if(res.inputAddresses!=null && this._senderAddress==null) {
|
|
1508
|
+
this._senderAddress = res.inputAddresses[1];
|
|
1223
1509
|
needsSave = true;
|
|
1224
1510
|
}
|
|
1225
1511
|
if(res.confirmations>=this.vaultRequiredConfirmations) {
|
|
1226
1512
|
if(
|
|
1227
|
-
this.
|
|
1228
|
-
this.
|
|
1229
|
-
this.
|
|
1513
|
+
this._state!==SpvFromBTCSwapState.BTC_TX_CONFIRMED &&
|
|
1514
|
+
this._state!==SpvFromBTCSwapState.FRONTED &&
|
|
1515
|
+
this._state!==SpvFromBTCSwapState.CLAIMED
|
|
1230
1516
|
) {
|
|
1231
|
-
this.
|
|
1517
|
+
this._state = SpvFromBTCSwapState.BTC_TX_CONFIRMED;
|
|
1232
1518
|
needsSave = true;
|
|
1233
1519
|
}
|
|
1234
1520
|
} else if(
|
|
1235
|
-
this.
|
|
1236
|
-
this.
|
|
1237
|
-
this.
|
|
1238
|
-
this.
|
|
1521
|
+
this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED ||
|
|
1522
|
+
this._state===SpvFromBTCSwapState.POSTED ||
|
|
1523
|
+
this._state===SpvFromBTCSwapState.SIGNED ||
|
|
1524
|
+
this._state===SpvFromBTCSwapState.DECLINED
|
|
1239
1525
|
) {
|
|
1240
|
-
this.
|
|
1526
|
+
this._state = SpvFromBTCSwapState.BROADCASTED;
|
|
1241
1527
|
needsSave = true;
|
|
1242
1528
|
}
|
|
1243
1529
|
if(needsSave && save) await this._saveAndEmit();
|
|
@@ -1249,41 +1535,39 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1249
1535
|
/**
|
|
1250
1536
|
* Checks the swap's state on-chain and compares it to its internal state, updates/changes it according to on-chain
|
|
1251
1537
|
* data
|
|
1252
|
-
*
|
|
1253
|
-
* @private
|
|
1254
1538
|
*/
|
|
1255
1539
|
private async syncStateFromChain(): Promise<boolean> {
|
|
1256
1540
|
let changed: boolean = false;
|
|
1257
1541
|
|
|
1258
1542
|
if(
|
|
1259
|
-
this.
|
|
1260
|
-
this.
|
|
1261
|
-
this.
|
|
1262
|
-
this.
|
|
1263
|
-
this.
|
|
1264
|
-
this.
|
|
1543
|
+
this._state===SpvFromBTCSwapState.SIGNED ||
|
|
1544
|
+
this._state===SpvFromBTCSwapState.POSTED ||
|
|
1545
|
+
this._state===SpvFromBTCSwapState.BROADCASTED ||
|
|
1546
|
+
this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED ||
|
|
1547
|
+
this._state===SpvFromBTCSwapState.DECLINED ||
|
|
1548
|
+
this._state===SpvFromBTCSwapState.BTC_TX_CONFIRMED
|
|
1265
1549
|
) {
|
|
1266
1550
|
//Check BTC transaction
|
|
1267
1551
|
if(await this._syncStateFromBitcoin(false)) changed ||= true;
|
|
1268
1552
|
}
|
|
1269
1553
|
|
|
1270
|
-
if(this.
|
|
1554
|
+
if(this._state===SpvFromBTCSwapState.BROADCASTED || this._state===SpvFromBTCSwapState.BTC_TX_CONFIRMED) {
|
|
1271
1555
|
if(await this._shouldCheckWithdrawalState()) {
|
|
1272
|
-
const status = await this.wrapper.
|
|
1273
|
-
this.logger.debug("syncStateFromChain(): status of "+this.
|
|
1556
|
+
const status = await this.wrapper._contract.getWithdrawalState(this._data!, this._genesisSmartChainBlockHeight);
|
|
1557
|
+
this.logger.debug("syncStateFromChain(): status of "+this._data!.btcTx.txid, status);
|
|
1274
1558
|
switch(status?.type) {
|
|
1275
1559
|
case SpvWithdrawalStateType.FRONTED:
|
|
1276
|
-
this.
|
|
1277
|
-
this.
|
|
1560
|
+
this._frontTxId = status.txId;
|
|
1561
|
+
this._state = SpvFromBTCSwapState.FRONTED;
|
|
1278
1562
|
changed ||= true;
|
|
1279
1563
|
break;
|
|
1280
1564
|
case SpvWithdrawalStateType.CLAIMED:
|
|
1281
|
-
this.
|
|
1282
|
-
this.
|
|
1565
|
+
this._claimTxId = status.txId;
|
|
1566
|
+
this._state = SpvFromBTCSwapState.CLAIMED;
|
|
1283
1567
|
changed ||= true;
|
|
1284
1568
|
break;
|
|
1285
1569
|
case SpvWithdrawalStateType.CLOSED:
|
|
1286
|
-
this.
|
|
1570
|
+
this._state = SpvFromBTCSwapState.CLOSED;
|
|
1287
1571
|
changed ||= true;
|
|
1288
1572
|
break;
|
|
1289
1573
|
}
|
|
@@ -1291,15 +1575,15 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1291
1575
|
}
|
|
1292
1576
|
|
|
1293
1577
|
if(
|
|
1294
|
-
this.
|
|
1295
|
-
this.
|
|
1296
|
-
this.
|
|
1578
|
+
this._state===SpvFromBTCSwapState.CREATED ||
|
|
1579
|
+
this._state===SpvFromBTCSwapState.SIGNED ||
|
|
1580
|
+
this._state===SpvFromBTCSwapState.POSTED
|
|
1297
1581
|
) {
|
|
1298
1582
|
if(this.expiry<Date.now()) {
|
|
1299
|
-
if(this.
|
|
1300
|
-
this.
|
|
1583
|
+
if(this._state===SpvFromBTCSwapState.CREATED) {
|
|
1584
|
+
this._state = SpvFromBTCSwapState.QUOTE_EXPIRED;
|
|
1301
1585
|
} else {
|
|
1302
|
-
this.
|
|
1586
|
+
this._state = SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED;
|
|
1303
1587
|
}
|
|
1304
1588
|
changed ||= true;
|
|
1305
1589
|
}
|
|
@@ -1308,27 +1592,35 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1308
1592
|
return changed;
|
|
1309
1593
|
}
|
|
1310
1594
|
|
|
1595
|
+
/**
|
|
1596
|
+
* @inheritDoc
|
|
1597
|
+
* @internal
|
|
1598
|
+
*/
|
|
1311
1599
|
async _sync(save?: boolean): Promise<boolean> {
|
|
1312
1600
|
const changed = await this.syncStateFromChain();
|
|
1313
1601
|
if(changed && save) await this._saveAndEmit();
|
|
1314
1602
|
return changed;
|
|
1315
1603
|
}
|
|
1316
1604
|
|
|
1605
|
+
/**
|
|
1606
|
+
* @inheritDoc
|
|
1607
|
+
* @internal
|
|
1608
|
+
*/
|
|
1317
1609
|
async _tick(save?: boolean): Promise<boolean> {
|
|
1318
1610
|
if(
|
|
1319
|
-
this.
|
|
1320
|
-
this.
|
|
1611
|
+
this._state===SpvFromBTCSwapState.CREATED ||
|
|
1612
|
+
this._state===SpvFromBTCSwapState.SIGNED
|
|
1321
1613
|
) {
|
|
1322
1614
|
if(this.getQuoteExpiry()<Date.now()) {
|
|
1323
|
-
this.
|
|
1615
|
+
this._state = SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED;
|
|
1324
1616
|
if(save) await this._saveAndEmit();
|
|
1325
1617
|
return true;
|
|
1326
1618
|
}
|
|
1327
1619
|
}
|
|
1328
1620
|
|
|
1329
|
-
if(this.
|
|
1621
|
+
if(this._state===SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED && !this.initiated) {
|
|
1330
1622
|
if(this.expiry<Date.now()) {
|
|
1331
|
-
this.
|
|
1623
|
+
this._state = SpvFromBTCSwapState.QUOTE_EXPIRED;
|
|
1332
1624
|
if(save) await this._saveAndEmit();
|
|
1333
1625
|
return true;
|
|
1334
1626
|
}
|
|
@@ -1336,8 +1628,8 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1336
1628
|
|
|
1337
1629
|
if(Math.floor(Date.now()/1000)%120===0) {
|
|
1338
1630
|
if (
|
|
1339
|
-
this.
|
|
1340
|
-
this.
|
|
1631
|
+
this._state === SpvFromBTCSwapState.POSTED ||
|
|
1632
|
+
this._state === SpvFromBTCSwapState.BROADCASTED
|
|
1341
1633
|
) {
|
|
1342
1634
|
try {
|
|
1343
1635
|
//Check if bitcoin payment was confirmed
|
|
@@ -1351,19 +1643,24 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1351
1643
|
return false;
|
|
1352
1644
|
}
|
|
1353
1645
|
|
|
1646
|
+
/**
|
|
1647
|
+
* Checks whether an on-chain withdrawal state should be fetched for this specific swap
|
|
1648
|
+
*
|
|
1649
|
+
* @internal
|
|
1650
|
+
*/
|
|
1354
1651
|
async _shouldCheckWithdrawalState(frontingAddress?: string | null, vaultDataUtxo?: string | null) {
|
|
1355
|
-
if(frontingAddress===undefined) frontingAddress = await this.wrapper.
|
|
1356
|
-
if(vaultDataUtxo===undefined) vaultDataUtxo = await this.wrapper.
|
|
1652
|
+
if(frontingAddress===undefined) frontingAddress = await this.wrapper._contract.getFronterAddress(this.vaultOwner, this.vaultId, this._data!);
|
|
1653
|
+
if(vaultDataUtxo===undefined) vaultDataUtxo = await this.wrapper._contract.getVaultLatestUtxo(this.vaultOwner, this.vaultId);
|
|
1357
1654
|
|
|
1358
1655
|
if(frontingAddress != null) return true; //In case the swap is fronted there will for sure be a fronted event
|
|
1359
1656
|
if(vaultDataUtxo == null) return true; //Vault UTXO is null (the vault closed)
|
|
1360
1657
|
|
|
1361
1658
|
const [txId, _] = vaultDataUtxo.split(":");
|
|
1362
1659
|
//Don't check both txns if their txId is equal
|
|
1363
|
-
if(this.
|
|
1660
|
+
if(this._data!.btcTx.txid===txId) return true;
|
|
1364
1661
|
const [btcTx, latestVaultTx] = await Promise.all([
|
|
1365
|
-
this.wrapper.
|
|
1366
|
-
this.wrapper.
|
|
1662
|
+
this.wrapper._btcRpc.getTransaction(this._data!.btcTx.txid),
|
|
1663
|
+
this.wrapper._btcRpc.getTransaction(txId)
|
|
1367
1664
|
]);
|
|
1368
1665
|
|
|
1369
1666
|
if(latestVaultTx==null || latestVaultTx.blockheight==null) {
|
|
@@ -1384,7 +1681,7 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
1384
1681
|
}
|
|
1385
1682
|
} else {
|
|
1386
1683
|
//Definitely not claimed because the transaction was probably double-spent (or evicted from mempool)
|
|
1387
|
-
this.logger.debug(`_shouldCheckWithdrawalState(): Skipped checking withdrawal state, btc tx probably replaced or evicted: ${this.
|
|
1684
|
+
this.logger.debug(`_shouldCheckWithdrawalState(): Skipped checking withdrawal state, btc tx probably replaced or evicted: ${this._data!.btcTx.txid} and not fronted`);
|
|
1388
1685
|
return false;
|
|
1389
1686
|
}
|
|
1390
1687
|
|