@atomiqlabs/sdk 8.8.3 → 8.9.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/api/index.d.ts +1 -0
- package/api/index.js +3 -0
- package/dist/ApiList.d.ts +37 -0
- package/dist/ApiList.js +30 -0
- package/dist/api/ApiEndpoints.d.ts +393 -0
- package/dist/api/ApiEndpoints.js +2 -0
- package/dist/api/ApiParser.d.ts +10 -0
- package/dist/api/ApiParser.js +134 -0
- package/dist/api/ApiTypes.d.ts +157 -0
- package/dist/api/ApiTypes.js +75 -0
- package/dist/api/SerializedAction.d.ts +40 -0
- package/dist/api/SerializedAction.js +59 -0
- package/dist/api/SwapperApi.d.ts +50 -0
- package/dist/api/SwapperApi.js +431 -0
- package/dist/api/index.d.ts +5 -0
- package/dist/api/index.js +24 -0
- package/dist/events/UnifiedSwapEventListener.d.ts +4 -3
- package/dist/events/UnifiedSwapEventListener.js +8 -2
- package/dist/http/HttpUtils.d.ts +4 -2
- package/dist/http/HttpUtils.js +10 -4
- package/dist/http/paramcoders/client/StreamingFetchPromise.d.ts +2 -1
- package/dist/http/paramcoders/client/StreamingFetchPromise.js +3 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/intermediaries/IntermediaryDiscovery.d.ts +7 -2
- package/dist/intermediaries/IntermediaryDiscovery.js +4 -4
- package/dist/intermediaries/apis/IntermediaryAPI.d.ts +171 -14
- package/dist/intermediaries/apis/IntermediaryAPI.js +174 -28
- package/dist/intermediaries/auth/SignedKeyBasedAuth.d.ts +14 -0
- package/dist/intermediaries/auth/SignedKeyBasedAuth.js +68 -0
- package/dist/storage/IUnifiedStorage.d.ts +45 -3
- package/dist/storage/UnifiedSwapStorage.d.ts +8 -2
- package/dist/storage/UnifiedSwapStorage.js +46 -8
- package/dist/swapper/Swapper.d.ts +41 -3
- package/dist/swapper/Swapper.js +93 -48
- package/dist/swapper/SwapperUtils.d.ts +18 -2
- package/dist/swapper/SwapperUtils.js +39 -1
- package/dist/swaps/ISwap.d.ts +70 -9
- package/dist/swaps/ISwap.js +28 -6
- package/dist/swaps/ISwapWrapper.d.ts +11 -1
- package/dist/swaps/ISwapWrapper.js +23 -3
- package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +1 -1
- package/dist/swaps/escrow_swaps/IEscrowSwap.js +4 -2
- package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +2 -1
- package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +2 -2
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +3 -1
- package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +3 -2
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +47 -31
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +201 -67
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +3 -1
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +6 -6
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +82 -15
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +304 -98
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +3 -1
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +6 -6
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +75 -42
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +424 -87
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +3 -1
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +7 -7
- package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +54 -11
- package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +214 -41
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +2 -1
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +7 -8
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +3 -1
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +5 -5
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +76 -19
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +290 -51
- package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +3 -1
- package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +5 -5
- package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +53 -12
- package/dist/swaps/trusted/ln/LnForGasSwap.js +163 -49
- package/dist/swaps/trusted/ln/LnForGasWrapper.js +1 -2
- package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +14 -13
- package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +30 -47
- package/dist/swaps/trusted/onchain/OnchainForGasWrapper.d.ts +3 -1
- package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +4 -4
- package/dist/types/SwapExecutionAction.d.ts +141 -34
- package/dist/types/SwapExecutionAction.js +104 -0
- package/dist/types/SwapExecutionStep.d.ts +144 -0
- package/dist/types/SwapExecutionStep.js +87 -0
- package/dist/types/TokenAmount.d.ts +6 -0
- package/dist/types/TokenAmount.js +26 -1
- package/dist/utils/BitcoinUtils.d.ts +2 -0
- package/dist/utils/BitcoinUtils.js +34 -1
- package/dist/utils/Utils.d.ts +3 -1
- package/dist/utils/Utils.js +7 -1
- package/package.json +7 -4
- package/src/api/ApiEndpoints.ts +427 -0
- package/src/api/ApiParser.ts +138 -0
- package/src/api/ApiTypes.ts +229 -0
- package/src/api/SerializedAction.ts +97 -0
- package/src/api/SwapperApi.ts +545 -0
- package/src/api/index.ts +5 -0
- package/src/events/UnifiedSwapEventListener.ts +11 -3
- package/src/http/HttpUtils.ts +10 -4
- package/src/http/paramcoders/client/StreamingFetchPromise.ts +4 -2
- package/src/index.ts +1 -0
- package/src/intermediaries/IntermediaryDiscovery.ts +9 -2
- package/src/intermediaries/apis/IntermediaryAPI.ts +314 -30
- package/src/intermediaries/auth/SignedKeyBasedAuth.ts +69 -0
- package/src/storage/IUnifiedStorage.ts +45 -4
- package/src/storage/UnifiedSwapStorage.ts +42 -8
- package/src/swapper/Swapper.ts +134 -52
- package/src/swapper/SwapperUtils.ts +42 -2
- package/src/swaps/ISwap.ts +88 -16
- package/src/swaps/ISwapWrapper.ts +28 -3
- package/src/swaps/escrow_swaps/IEscrowSwap.ts +5 -3
- package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +3 -1
- package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +4 -1
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +264 -67
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +6 -4
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +390 -89
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +6 -4
- package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +548 -94
- package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +7 -5
- package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +276 -45
- package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +7 -6
- package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +5 -3
- package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +393 -57
- package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +5 -3
- package/src/swaps/trusted/ln/LnForGasSwap.ts +211 -47
- package/src/swaps/trusted/ln/LnForGasWrapper.ts +1 -2
- package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +32 -51
- package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +5 -3
- package/src/types/SwapExecutionAction.ts +266 -43
- package/src/types/SwapExecutionStep.ts +224 -0
- package/src/types/TokenAmount.ts +36 -2
- package/src/utils/BitcoinUtils.ts +32 -0
- package/src/utils/Utils.ts +10 -1
- package/src/intermediaries/apis/TrustedIntermediaryAPI.ts +0 -258
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
getTxoHash, toBigInt
|
|
16
16
|
} from "../../../../utils/Utils";
|
|
17
17
|
import {
|
|
18
|
-
fromOutputScript,
|
|
18
|
+
fromOutputScript, getSenderAddress, getVoutIndex,
|
|
19
19
|
parsePsbtTransaction,
|
|
20
20
|
toOutputScript,
|
|
21
21
|
} from "../../../../utils/BitcoinUtils";
|
|
@@ -33,8 +33,20 @@ import {IAddressSwap} from "../../../IAddressSwap";
|
|
|
33
33
|
import {TokenAmount, toTokenAmount} from "../../../../types/TokenAmount";
|
|
34
34
|
import {BitcoinTokens, BtcToken, SCToken} from "../../../../types/Token";
|
|
35
35
|
import {getLogger, LoggerType} from "../../../../utils/Logger";
|
|
36
|
+
import {timeoutPromise} from "../../../../utils/TimeoutUtils";
|
|
36
37
|
import {toBitcoinWallet} from "../../../../utils/BitcoinWalletUtils";
|
|
37
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
SwapExecutionActionSendToAddress,
|
|
40
|
+
SwapExecutionActionSignPSBT,
|
|
41
|
+
SwapExecutionActionSignSmartChainTx,
|
|
42
|
+
SwapExecutionActionWait
|
|
43
|
+
} from "../../../../types/SwapExecutionAction";
|
|
44
|
+
import {
|
|
45
|
+
SwapExecutionStepPayment,
|
|
46
|
+
SwapExecutionStepSettlement,
|
|
47
|
+
SwapExecutionStepSetup
|
|
48
|
+
} from "../../../../types/SwapExecutionStep";
|
|
49
|
+
import {SwapStateInfo} from "../../../../types/SwapStateInfo";
|
|
38
50
|
|
|
39
51
|
/**
|
|
40
52
|
* State enum for legacy escrow based Bitcoin -> Smart chain swaps.
|
|
@@ -264,6 +276,32 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
264
276
|
return this.txId ?? null;
|
|
265
277
|
}
|
|
266
278
|
|
|
279
|
+
private async _setSubmittedBitcoinTx(txId: string, psbt?: Transaction): Promise<void> {
|
|
280
|
+
let changed = false;
|
|
281
|
+
if(this.txId!==txId) {
|
|
282
|
+
this.txId = txId;
|
|
283
|
+
changed = true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const submittedVout = this.address==null || this.amount==null || psbt==null
|
|
287
|
+
? undefined
|
|
288
|
+
: getVoutIndex(psbt, this.wrapper._options.bitcoinNetwork, this.address, this.amount);
|
|
289
|
+
if(submittedVout!=null && this.vout!==submittedVout) {
|
|
290
|
+
this.vout = submittedVout;
|
|
291
|
+
changed = true;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const submittedSenderAddress = psbt==null
|
|
295
|
+
? undefined
|
|
296
|
+
: getSenderAddress(psbt, this.wrapper._options.bitcoinNetwork);
|
|
297
|
+
if(submittedSenderAddress!=null && this.senderAddress!==submittedSenderAddress) {
|
|
298
|
+
this.senderAddress = submittedSenderAddress;
|
|
299
|
+
changed = true;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if(changed) await this._saveAndEmit();
|
|
303
|
+
}
|
|
304
|
+
|
|
267
305
|
/**
|
|
268
306
|
* Returns timeout time (in UNIX milliseconds) when the on-chain address will expire and no funds should be sent
|
|
269
307
|
* to that address anymore
|
|
@@ -507,7 +545,12 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
507
545
|
requiredConfirmations = this.inferRequiredConfirmationsCount(btcTx, vout);
|
|
508
546
|
}
|
|
509
547
|
|
|
510
|
-
if(btcTx!=null && (
|
|
548
|
+
if(btcTx!=null && (
|
|
549
|
+
btcTx.txid!==this.txId ||
|
|
550
|
+
this.vout==null ||
|
|
551
|
+
this.senderAddress==null ||
|
|
552
|
+
(this.requiredConfirmations==null && requiredConfirmations!=null)
|
|
553
|
+
)) {
|
|
511
554
|
this.txId = btcTx.txid;
|
|
512
555
|
this.vout = vout;
|
|
513
556
|
this.requiredConfirmations = requiredConfirmations;
|
|
@@ -571,7 +614,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
571
614
|
_bitcoinWallet: IBitcoinWallet | MinimalBitcoinWalletInterface,
|
|
572
615
|
feeRate?: number,
|
|
573
616
|
additionalOutputs?: ({amount: bigint, outputScript: Uint8Array} | {amount: bigint, address: string})[]
|
|
574
|
-
): Promise<{psbt: Transaction, psbtHex: string, psbtBase64: string, signInputs: number[]}> {
|
|
617
|
+
): Promise<{psbt: Transaction, psbtHex: string, psbtBase64: string, signInputs: number[], feeRate: number}> {
|
|
575
618
|
if(this.address==null) throw new Error("Cannot create funded PSBT, because the address is not known! This can happen after a swap is recovered.");
|
|
576
619
|
|
|
577
620
|
let bitcoinWallet: IBitcoinWallet;
|
|
@@ -611,7 +654,8 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
611
654
|
psbt,
|
|
612
655
|
psbtHex: serializedPsbt.toString("hex"),
|
|
613
656
|
psbtBase64: serializedPsbt.toString("base64"),
|
|
614
|
-
signInputs
|
|
657
|
+
signInputs,
|
|
658
|
+
feeRate
|
|
615
659
|
};
|
|
616
660
|
}
|
|
617
661
|
|
|
@@ -625,6 +669,8 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
625
669
|
) {
|
|
626
670
|
if(this._state!==FromBTCSwapState.CLAIM_COMMITED)
|
|
627
671
|
throw new Error("Swap not committed yet, please initiate the swap first with commit() call!");
|
|
672
|
+
if(this.txId!=null)
|
|
673
|
+
throw new Error("Bitcoin transaction already submitted for this swap!");
|
|
628
674
|
return this._getFundedPsbt(_bitcoinWallet, feeRate, additionalOutputs);
|
|
629
675
|
}
|
|
630
676
|
|
|
@@ -638,6 +684,8 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
638
684
|
const psbt = parsePsbtTransaction(_psbt);
|
|
639
685
|
if(this._state!==FromBTCSwapState.CLAIM_COMMITED)
|
|
640
686
|
throw new Error("Swap not committed yet, please initiate the swap first with commit() call!");
|
|
687
|
+
if(this.txId!=null)
|
|
688
|
+
throw new Error("Bitcoin transaction already submitted for this swap!");
|
|
641
689
|
|
|
642
690
|
//Ensure not expired
|
|
643
691
|
if(this.getTimeoutTime()<Date.now()) {
|
|
@@ -655,7 +703,9 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
655
703
|
|
|
656
704
|
if(!psbt.isFinal) psbt.finalize();
|
|
657
705
|
|
|
658
|
-
|
|
706
|
+
const txId = await this.wrapper._btcRpc.sendRawTransaction(Buffer.from(psbt.toBytes(true, true)).toString("hex"));
|
|
707
|
+
await this._setSubmittedBitcoinTx(txId, psbt);
|
|
708
|
+
return txId;
|
|
659
709
|
}
|
|
660
710
|
|
|
661
711
|
/**
|
|
@@ -677,6 +727,8 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
677
727
|
|
|
678
728
|
if(this._state!==FromBTCSwapState.CLAIM_COMMITED)
|
|
679
729
|
throw new Error("Swap not committed yet, please initiate the swap first with commit() call!");
|
|
730
|
+
if(this.txId!=null)
|
|
731
|
+
throw new Error("Bitcoin transaction already submitted for this swap!");
|
|
680
732
|
|
|
681
733
|
//Ensure not expired
|
|
682
734
|
if(this.getTimeoutTime()<Date.now()) {
|
|
@@ -684,7 +736,9 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
684
736
|
}
|
|
685
737
|
|
|
686
738
|
if(isIBitcoinWallet(wallet)) {
|
|
687
|
-
|
|
739
|
+
const txId = await wallet.sendTransaction(this.address, this.amount, feeRate);
|
|
740
|
+
await this._setSubmittedBitcoinTx(txId);
|
|
741
|
+
return txId;
|
|
688
742
|
} else {
|
|
689
743
|
const {psbt, psbtHex, psbtBase64, signInputs} = await this.getFundedPsbt(wallet, feeRate);
|
|
690
744
|
const signedPsbt = await wallet.signPsbt({
|
|
@@ -742,7 +796,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
742
796
|
if(wallet!=null) {
|
|
743
797
|
const bitcoinPaymentSent = await this.getBitcoinPayment();
|
|
744
798
|
|
|
745
|
-
if(bitcoinPaymentSent==null) {
|
|
799
|
+
if(bitcoinPaymentSent==null && this.txId==null) {
|
|
746
800
|
//Send btc tx
|
|
747
801
|
const txId = await this.sendBitcoinTransaction(wallet, options?.feeRate);
|
|
748
802
|
if(callbacks?.onSourceTransactionSent!=null) callbacks.onSourceTransactionSent(txId);
|
|
@@ -766,74 +820,421 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
766
820
|
}
|
|
767
821
|
|
|
768
822
|
/**
|
|
769
|
-
* @
|
|
770
|
-
*
|
|
771
|
-
* @param options.bitcoinFeeRate Optional fee rate to use for the created Bitcoin transaction
|
|
772
|
-
* @param options.bitcoinWallet Bitcoin wallet to use, when provided the function returns a funded
|
|
773
|
-
* psbt (`"FUNDED_PSBT"`), if not passed just a bitcoin receive address is returned (`"ADDRESS"`)
|
|
774
|
-
* @param options.skipChecks Skip checks like making sure init signature is still valid and swap
|
|
775
|
-
* wasn't commited yet (this is handled on swap creation, if you commit right after quoting, you
|
|
776
|
-
* can use `skipChecks=true`)
|
|
777
|
-
*
|
|
778
|
-
* @throws {Error} if the swap or quote is expired, or if triggered in invalid state
|
|
823
|
+
* @internal
|
|
779
824
|
*/
|
|
780
|
-
async
|
|
781
|
-
|
|
782
|
-
bitcoinWallet?: MinimalBitcoinWalletInterface,
|
|
783
|
-
skipChecks?: boolean
|
|
825
|
+
protected async _getExecutionStatus(options?: {
|
|
826
|
+
maxWaitTillAutomaticSettlementSeconds?: number
|
|
784
827
|
}) {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
828
|
+
const state = this._state;
|
|
829
|
+
const now = Date.now();
|
|
830
|
+
const timeoutTime = this.getTimeoutTime();
|
|
831
|
+
|
|
832
|
+
let confirmations: {
|
|
833
|
+
current: number,
|
|
834
|
+
target: number,
|
|
835
|
+
etaSeconds: number
|
|
836
|
+
} | undefined;
|
|
837
|
+
let bitcoinTxId: string | undefined;
|
|
838
|
+
|
|
839
|
+
let destinationSetupStatus: SwapExecutionStepSetup<T["ChainId"]>["status"] = "awaiting";
|
|
840
|
+
let bitcoinPaymentStatus: SwapExecutionStepPayment<"BITCOIN">["status"] = "inactive";
|
|
841
|
+
let destinationSettlementStatus: SwapExecutionStepSettlement<T["ChainId"], "awaiting_automatic" | "awaiting_manual">["status"] = "inactive";
|
|
842
|
+
let buildCurrentAction: (actionOptions?: {
|
|
843
|
+
bitcoinFeeRate?: number,
|
|
844
|
+
bitcoinWallet?: MinimalBitcoinWalletInterface,
|
|
845
|
+
skipChecks?: boolean,
|
|
846
|
+
manualSettlementSmartChainSigner?: string | T["Signer"] | T["NativeSigner"],
|
|
847
|
+
}) => Promise<
|
|
848
|
+
SwapExecutionActionSendToAddress<false> |
|
|
849
|
+
SwapExecutionActionSignPSBT<"FUNDED_PSBT"> |
|
|
850
|
+
SwapExecutionActionWait<"BITCOIN_CONFS" | "SETTLEMENT"> |
|
|
851
|
+
SwapExecutionActionSignSmartChainTx<T> |
|
|
852
|
+
undefined
|
|
853
|
+
> = async () => undefined;
|
|
854
|
+
|
|
855
|
+
switch(state) {
|
|
856
|
+
case FromBTCSwapState.PR_CREATED: {
|
|
857
|
+
const quoteValid = await this._verifyQuoteValid();
|
|
858
|
+
destinationSetupStatus = quoteValid && timeoutTime>=now ? "awaiting" : "soft_expired";
|
|
859
|
+
if(quoteValid && timeoutTime>=now) {
|
|
860
|
+
buildCurrentAction = this._buildInitSmartChainTxAction.bind(this);
|
|
861
|
+
}
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
case FromBTCSwapState.QUOTE_SOFT_EXPIRED:
|
|
865
|
+
destinationSetupStatus = "soft_expired";
|
|
866
|
+
break;
|
|
867
|
+
case FromBTCSwapState.QUOTE_EXPIRED:
|
|
868
|
+
destinationSetupStatus = "expired";
|
|
869
|
+
break;
|
|
870
|
+
case FromBTCSwapState.CLAIM_COMMITED:
|
|
871
|
+
case FromBTCSwapState.EXPIRED:
|
|
872
|
+
case FromBTCSwapState.FAILED:
|
|
873
|
+
const bitcoinPayment = this.address==null ? null : await this.getBitcoinPayment();
|
|
874
|
+
bitcoinTxId = bitcoinPayment?.txId;
|
|
875
|
+
let bitcoinConfirmationDelay: number | undefined;
|
|
876
|
+
if(bitcoinPayment!=null && bitcoinPayment.confirmations < bitcoinPayment.targetConfirmations) {
|
|
877
|
+
const tx = await this.wrapper._btcRpc.getTransaction(bitcoinPayment.txId);
|
|
878
|
+
const result = tx==null
|
|
879
|
+
? null
|
|
880
|
+
: await this.wrapper._btcRpc.getConfirmationDelay(tx, bitcoinPayment.targetConfirmations);
|
|
881
|
+
bitcoinConfirmationDelay = result ?? -1;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
destinationSetupStatus = "completed";
|
|
885
|
+
if(bitcoinPayment==null) {
|
|
886
|
+
if(this.txId!=null) {
|
|
887
|
+
bitcoinPaymentStatus = state===FromBTCSwapState.FAILED ? "expired" : "received";
|
|
888
|
+
if(state!==FromBTCSwapState.FAILED) {
|
|
889
|
+
buildCurrentAction = this._buildWaitBitcoinConfirmationsAction.bind(this, -1, "Wait for bitcoin transaction to be picked up by the RPC and confirmed.");
|
|
890
|
+
}
|
|
891
|
+
} else {
|
|
892
|
+
bitcoinPaymentStatus = "awaiting";
|
|
893
|
+
if(state===FromBTCSwapState.EXPIRED) bitcoinPaymentStatus = "soft_expired";
|
|
894
|
+
if(state===FromBTCSwapState.FAILED) bitcoinPaymentStatus = "expired";
|
|
895
|
+
if(
|
|
896
|
+
state===FromBTCSwapState.CLAIM_COMMITED && timeoutTime>=now &&
|
|
897
|
+
this.address!=null && this.amount!=null
|
|
898
|
+
) {
|
|
899
|
+
buildCurrentAction = this._buildSendToAddressOrSignPsbtAction.bind(this);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
} else if(bitcoinPayment.confirmations >= bitcoinPayment.targetConfirmations) {
|
|
903
|
+
bitcoinPaymentStatus = "confirmed";
|
|
904
|
+
if(state!==FromBTCSwapState.FAILED) {
|
|
905
|
+
buildCurrentAction = this._buildWaitBitcoinConfirmationsAction.bind(this, bitcoinConfirmationDelay ?? -1, undefined);
|
|
906
|
+
}
|
|
907
|
+
} else {
|
|
908
|
+
bitcoinPaymentStatus = "received";
|
|
909
|
+
confirmations = {
|
|
910
|
+
current: bitcoinPayment.confirmations,
|
|
911
|
+
target: bitcoinPayment.targetConfirmations,
|
|
912
|
+
etaSeconds: bitcoinConfirmationDelay ?? -1
|
|
913
|
+
};
|
|
914
|
+
if(state!==FromBTCSwapState.FAILED) {
|
|
915
|
+
buildCurrentAction = this._buildWaitBitcoinConfirmationsAction.bind(this, bitcoinConfirmationDelay ?? -1, undefined);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
destinationSettlementStatus = state===FromBTCSwapState.FAILED ? "expired" : "inactive";
|
|
919
|
+
break;
|
|
920
|
+
case FromBTCSwapState.BTC_TX_CONFIRMED:
|
|
921
|
+
destinationSetupStatus = "completed";
|
|
922
|
+
bitcoinPaymentStatus = "confirmed";
|
|
923
|
+
if(
|
|
924
|
+
this.btcTxConfirmedAt==null ||
|
|
925
|
+
options?.maxWaitTillAutomaticSettlementSeconds===0 ||
|
|
926
|
+
(now - this.btcTxConfirmedAt) > (options?.maxWaitTillAutomaticSettlementSeconds ?? 60)*1000
|
|
927
|
+
) {
|
|
928
|
+
destinationSettlementStatus = "awaiting_manual";
|
|
929
|
+
buildCurrentAction = this._buildClaimSmartChainTxAction.bind(this);
|
|
930
|
+
} else {
|
|
931
|
+
destinationSettlementStatus = "awaiting_automatic";
|
|
932
|
+
buildCurrentAction = this._buildWaitSettlementAction.bind(this, options?.maxWaitTillAutomaticSettlementSeconds);
|
|
933
|
+
}
|
|
934
|
+
break;
|
|
935
|
+
case FromBTCSwapState.CLAIM_CLAIMED:
|
|
936
|
+
destinationSetupStatus = "completed";
|
|
937
|
+
bitcoinPaymentStatus = "confirmed";
|
|
938
|
+
destinationSettlementStatus = "settled";
|
|
939
|
+
break;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
if(bitcoinPaymentStatus==="confirmed") {
|
|
943
|
+
const requiredConfirmations = this.getRequiredConfirmationsCount();
|
|
944
|
+
if(!Number.isNaN(requiredConfirmations)) {
|
|
945
|
+
confirmations = {
|
|
946
|
+
current: requiredConfirmations,
|
|
947
|
+
target: requiredConfirmations,
|
|
948
|
+
etaSeconds: 0
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
return {
|
|
954
|
+
steps: [
|
|
789
955
|
{
|
|
790
|
-
|
|
791
|
-
|
|
956
|
+
type: "Setup",
|
|
957
|
+
side: "destination",
|
|
792
958
|
chain: this.chainIdentifier,
|
|
793
|
-
|
|
959
|
+
title: "Open Bitcoin swap address",
|
|
960
|
+
description: `Create the escrow on the ${this.chainIdentifier} side to open the Bitcoin swap address`,
|
|
961
|
+
status: destinationSetupStatus,
|
|
962
|
+
setupTxId: this._commitTxId
|
|
794
963
|
},
|
|
795
964
|
{
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
chain: "BITCOIN"
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
965
|
+
type: "Payment",
|
|
966
|
+
side: "source",
|
|
967
|
+
chain: "BITCOIN",
|
|
968
|
+
title: "Bitcoin payment",
|
|
969
|
+
description: "Send Bitcoin to the swap address and wait for the transaction to confirm",
|
|
970
|
+
status: bitcoinPaymentStatus,
|
|
971
|
+
confirmations,
|
|
972
|
+
initTxId: this.txId ?? bitcoinTxId,
|
|
973
|
+
settleTxId: this.txId
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
type: "Settlement",
|
|
977
|
+
side: "destination",
|
|
978
|
+
chain: this.chainIdentifier,
|
|
979
|
+
title: "Destination settlement",
|
|
980
|
+
description: `Wait for automatic settlement on the ${this.chainIdentifier} side, or settle manually if it takes too long`,
|
|
981
|
+
status: destinationSettlementStatus,
|
|
982
|
+
initTxId: this._commitTxId,
|
|
983
|
+
settleTxId: this._claimTxId
|
|
984
|
+
}
|
|
985
|
+
] as [
|
|
986
|
+
SwapExecutionStepSetup<T["ChainId"]>,
|
|
987
|
+
SwapExecutionStepPayment<"BITCOIN">,
|
|
988
|
+
SwapExecutionStepSettlement<T["ChainId"], "awaiting_automatic" | "awaiting_manual">
|
|
989
|
+
],
|
|
990
|
+
buildCurrentAction,
|
|
991
|
+
state
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* @inheritDoc
|
|
997
|
+
* @internal
|
|
998
|
+
*/
|
|
999
|
+
async _submitExecutionTransactions(txs: (T["SignedTXType"] | Transaction | string)[], abortSignal?: AbortSignal, requiredStates?: FromBTCSwapState[], idempotent?: boolean): Promise<string[]> {
|
|
1000
|
+
if(txs.length===0) throw new Error("Need to submit at least 1 transaction in the array, submitted empty array of transactions!");
|
|
1001
|
+
|
|
1002
|
+
if(idempotent) {
|
|
1003
|
+
// Handle idempotent calls
|
|
1004
|
+
let idempotencyTriggered = false;
|
|
1005
|
+
const txIds: string[] = [];
|
|
1006
|
+
for(let tx of txs) {
|
|
1007
|
+
let parsedTx: T["SignedTXType"] | Transaction | undefined;
|
|
1008
|
+
if(typeof(tx)==="string") {
|
|
1009
|
+
try {
|
|
1010
|
+
parsedTx = await this.wrapper._chain.deserializeSignedTx(tx);
|
|
1011
|
+
} catch (e) {}
|
|
1012
|
+
try {
|
|
1013
|
+
parsedTx = parsePsbtTransaction(tx);
|
|
1014
|
+
} catch (e) {}
|
|
1015
|
+
} else {
|
|
1016
|
+
parsedTx = tx;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
if(parsedTx==null) {
|
|
1020
|
+
this.logger.debug("_submitExecutionTransactions(): Failed to parse provided execution transaction: ", tx);
|
|
1021
|
+
continue;
|
|
810
1022
|
}
|
|
811
|
-
|
|
1023
|
+
|
|
1024
|
+
if(parsedTx instanceof Transaction) {
|
|
1025
|
+
// Bitcoin tx
|
|
1026
|
+
const btcTx = await this.wrapper._btcRpc.parseTransaction(Buffer.from(parsedTx.toBytes(true)).toString("hex"));
|
|
1027
|
+
if(btcTx.txid===this.txId) idempotencyTriggered = true;
|
|
1028
|
+
txIds.push(btcTx.txid);
|
|
1029
|
+
} else {
|
|
1030
|
+
// SC tx
|
|
1031
|
+
if(this.wrapper._chain.getTxId!=null) {
|
|
1032
|
+
const txId = await this.wrapper._chain.getTxId(parsedTx);
|
|
1033
|
+
if(this._commitTxId===txId || this._claimTxId===txId) idempotencyTriggered = true;
|
|
1034
|
+
txIds.push(txId);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
if(idempotencyTriggered) return txIds;
|
|
812
1039
|
}
|
|
813
1040
|
|
|
1041
|
+
if(requiredStates!=null && !requiredStates.includes(this._state)) throw new Error("Swap state has changed before transactions were submitted!");
|
|
1042
|
+
|
|
814
1043
|
if(this._state===FromBTCSwapState.CLAIM_COMMITED) {
|
|
1044
|
+
let psbt: string | Transaction;
|
|
1045
|
+
if(txs.length!==1) throw new Error("Need to submit exactly 1 signed PSBT!");
|
|
1046
|
+
if(typeof(txs[0])!=="string" && !(txs[0] instanceof Transaction))
|
|
1047
|
+
throw new Error("Must submit a valid PSBT as hex/base64 string or `@scure/btc-signer` Transaction object!");
|
|
1048
|
+
psbt = txs[0];
|
|
1049
|
+
return [await this.submitPsbt(psbt)];
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
if(this._state===FromBTCSwapState.PR_CREATED || this._state===FromBTCSwapState.QUOTE_SOFT_EXPIRED) {
|
|
1053
|
+
if(!await this._verifyQuoteValid()) throw new Error("Quote is already expired!");
|
|
815
1054
|
if(this.getTimeoutTime()<Date.now()) throw new Error("Swap address already expired or close to expiry!");
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1055
|
+
|
|
1056
|
+
const parsedTxs: T["SignedTXType"][] = [];
|
|
1057
|
+
for(let tx of txs) {
|
|
1058
|
+
parsedTxs.push(typeof(tx)==="string" ? await this.wrapper._chain.deserializeSignedTx(tx) : tx);
|
|
1059
|
+
}
|
|
1060
|
+
const txIds = await this.wrapper._chain.sendSignedAndConfirm(parsedTxs, true, abortSignal, false);
|
|
1061
|
+
await this.waitTillCommited(abortSignal);
|
|
1062
|
+
return txIds;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
if(this._state===FromBTCSwapState.BTC_TX_CONFIRMED) {
|
|
1066
|
+
const parsedTxs: T["SignedTXType"][] = [];
|
|
1067
|
+
for(let tx of txs) {
|
|
1068
|
+
parsedTxs.push(typeof(tx)==="string" ? await this.wrapper._chain.deserializeSignedTx(tx) : tx);
|
|
1069
|
+
}
|
|
1070
|
+
const txIds = await this.wrapper._chain.sendSignedAndConfirm(parsedTxs, true, abortSignal, false);
|
|
1071
|
+
await this.waitTillClaimed(undefined, abortSignal);
|
|
1072
|
+
return txIds;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
throw new Error("Invalid swap state for transaction submission!");
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* @internal
|
|
1080
|
+
*/
|
|
1081
|
+
private async _buildSendToAddressOrSignPsbtAction(actionOptions?: {
|
|
1082
|
+
bitcoinFeeRate?: number,
|
|
1083
|
+
bitcoinWallet?: MinimalBitcoinWalletInterface,
|
|
1084
|
+
}): Promise<
|
|
1085
|
+
SwapExecutionActionSendToAddress<false> |
|
|
1086
|
+
SwapExecutionActionSignPSBT<"FUNDED_PSBT">
|
|
1087
|
+
> {
|
|
1088
|
+
if(this.address==null) throw new Error("Bitcoin swap address not known!");
|
|
1089
|
+
if(this.amount==null) throw new Error("Bitcoin swap amount not known!");
|
|
1090
|
+
|
|
1091
|
+
if(actionOptions?.bitcoinWallet==null) {
|
|
1092
|
+
return {
|
|
1093
|
+
type: "SendToAddress",
|
|
1094
|
+
name: "Deposit on Bitcoin",
|
|
1095
|
+
description: "Send funds to the bitcoin swap address",
|
|
1096
|
+
chain: "BITCOIN",
|
|
1097
|
+
txs: [{
|
|
1098
|
+
type: "BITCOIN_ADDRESS",
|
|
1099
|
+
address: this.address,
|
|
1100
|
+
hyperlink: this._getHyperlink(),
|
|
1101
|
+
amount: toTokenAmount(this.amount, BitcoinTokens.BTC, this.wrapper._prices)
|
|
1102
|
+
}],
|
|
1103
|
+
waitForTransactions: async (
|
|
1104
|
+
maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal
|
|
1105
|
+
) => {
|
|
1106
|
+
let btcTxId: string | undefined;
|
|
1107
|
+
const abortController = extendAbortController(
|
|
1108
|
+
abortSignal, maxWaitTimeSeconds, "Timed out waiting for bitcoin transaction"
|
|
1109
|
+
);
|
|
1110
|
+
|
|
1111
|
+
try {
|
|
1112
|
+
return await this.waitForBitcoinTransaction(
|
|
1113
|
+
(txId) => {
|
|
1114
|
+
btcTxId = txId;
|
|
1115
|
+
abortController.abort();
|
|
1116
|
+
},
|
|
1117
|
+
pollIntervalSeconds,
|
|
1118
|
+
abortController.signal
|
|
1119
|
+
);
|
|
1120
|
+
} catch (e) {
|
|
1121
|
+
if(btcTxId!=null) return btcTxId;
|
|
1122
|
+
throw e;
|
|
1123
|
+
}
|
|
832
1124
|
}
|
|
833
|
-
|
|
1125
|
+
} as SwapExecutionActionSendToAddress<false>;
|
|
834
1126
|
}
|
|
835
1127
|
|
|
836
|
-
|
|
1128
|
+
return {
|
|
1129
|
+
type: "SignPSBT",
|
|
1130
|
+
name: "Deposit on Bitcoin",
|
|
1131
|
+
description: "Send funds to the bitcoin swap address",
|
|
1132
|
+
chain: "BITCOIN",
|
|
1133
|
+
txs: [{
|
|
1134
|
+
...await this.getFundedPsbt(actionOptions.bitcoinWallet, actionOptions?.bitcoinFeeRate),
|
|
1135
|
+
type: "FUNDED_PSBT"
|
|
1136
|
+
}],
|
|
1137
|
+
submitPsbt: async (signedPsbt: string | Transaction | (string | Transaction)[], idempotent?: boolean) => {
|
|
1138
|
+
return this._submitExecutionTransactions(
|
|
1139
|
+
Array.isArray(signedPsbt) ? signedPsbt : [signedPsbt],
|
|
1140
|
+
undefined,
|
|
1141
|
+
[FromBTCSwapState.CLAIM_COMMITED],
|
|
1142
|
+
idempotent
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
} as SwapExecutionActionSignPSBT<"FUNDED_PSBT">;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/**
|
|
1149
|
+
* @internal
|
|
1150
|
+
*/
|
|
1151
|
+
private async _buildWaitBitcoinConfirmationsAction(confirmationDelay: number, description?: string): Promise<SwapExecutionActionWait<"BITCOIN_CONFS">> {
|
|
1152
|
+
return {
|
|
1153
|
+
type: "Wait",
|
|
1154
|
+
name: "Bitcoin confirmations",
|
|
1155
|
+
description: description ?? "Wait for bitcoin transaction to confirm",
|
|
1156
|
+
pollTimeSeconds: 10,
|
|
1157
|
+
expectedTimeSeconds: confirmationDelay===-1 ? -1 : Math.floor(confirmationDelay/1000),
|
|
1158
|
+
wait: async (
|
|
1159
|
+
maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal,
|
|
1160
|
+
btcConfirmationsCallback?: (txId?: string, confirmations?: number, targetConfirmations?: number, txEtaMs?: number) => void
|
|
1161
|
+
) => {
|
|
1162
|
+
const abortController = extendAbortController(
|
|
1163
|
+
abortSignal, maxWaitTimeSeconds, "Timed out waiting for bitcoin transaction to confirm"
|
|
1164
|
+
);
|
|
1165
|
+
await this.waitForBitcoinTransaction(btcConfirmationsCallback, pollIntervalSeconds, abortController.signal);
|
|
1166
|
+
}
|
|
1167
|
+
} as SwapExecutionActionWait<"BITCOIN_CONFS">;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
/**
|
|
1171
|
+
* @internal
|
|
1172
|
+
*/
|
|
1173
|
+
private async _buildWaitSettlementAction(maxWaitTillAutomaticSettlementSeconds?: number): Promise<SwapExecutionActionWait<"SETTLEMENT">> {
|
|
1174
|
+
return {
|
|
1175
|
+
type: "Wait",
|
|
1176
|
+
name: "Automatic settlement",
|
|
1177
|
+
description: "Wait for automatic settlement by the watchtower",
|
|
1178
|
+
pollTimeSeconds: 5,
|
|
1179
|
+
expectedTimeSeconds: 10,
|
|
1180
|
+
wait: async (
|
|
1181
|
+
maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal
|
|
1182
|
+
) => {
|
|
1183
|
+
await this.waitTillClaimed(maxWaitTimeSeconds ?? maxWaitTillAutomaticSettlementSeconds ?? 60, abortSignal, pollIntervalSeconds);
|
|
1184
|
+
}
|
|
1185
|
+
} as SwapExecutionActionWait<"SETTLEMENT">;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* @internal
|
|
1190
|
+
*/
|
|
1191
|
+
private async _buildInitSmartChainTxAction(actionOptions?: {
|
|
1192
|
+
skipChecks?: boolean,
|
|
1193
|
+
}): Promise<SwapExecutionActionSignSmartChainTx<T>> {
|
|
1194
|
+
return {
|
|
1195
|
+
type: "SignSmartChainTransaction",
|
|
1196
|
+
name: "Initiate swap",
|
|
1197
|
+
description: `Opens up the bitcoin swap address on the ${this.chainIdentifier} side`,
|
|
1198
|
+
chain: this.chainIdentifier,
|
|
1199
|
+
txs: await this.prepareTransactions(this.txsCommit(actionOptions?.skipChecks)),
|
|
1200
|
+
submitTransactions: async (txs: (T["SignedTXType"] | string)[], abortSignal?: AbortSignal, idempotent?: boolean) => {
|
|
1201
|
+
return this._submitExecutionTransactions(
|
|
1202
|
+
txs,
|
|
1203
|
+
abortSignal,
|
|
1204
|
+
[FromBTCSwapState.PR_CREATED, FromBTCSwapState.QUOTE_SOFT_EXPIRED],
|
|
1205
|
+
idempotent
|
|
1206
|
+
);
|
|
1207
|
+
},
|
|
1208
|
+
requiredSigner: this._getInitiator()
|
|
1209
|
+
} as SwapExecutionActionSignSmartChainTx<T>;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* @inheritDoc
|
|
1214
|
+
* @internal
|
|
1215
|
+
*/
|
|
1216
|
+
private async _buildClaimSmartChainTxAction(actionOptions?: {
|
|
1217
|
+
manualSettlementSmartChainSigner?: string | T["Signer"] | T["NativeSigner"],
|
|
1218
|
+
}): Promise<SwapExecutionActionSignSmartChainTx<T>> {
|
|
1219
|
+
const signerAddress =
|
|
1220
|
+
await this.wrapper._getSignerAddress(actionOptions?.manualSettlementSmartChainSigner);
|
|
1221
|
+
|
|
1222
|
+
return {
|
|
1223
|
+
type: "SignSmartChainTransaction",
|
|
1224
|
+
name: "Settle manually",
|
|
1225
|
+
description: "Manually settle (claim) the swap on the destination smart chain",
|
|
1226
|
+
chain: this.chainIdentifier,
|
|
1227
|
+
txs: await this.prepareTransactions(this.txsClaim(actionOptions?.manualSettlementSmartChainSigner)),
|
|
1228
|
+
submitTransactions: async (txs: (T["SignedTXType"] | string)[], abortSignal?: AbortSignal, idempotent?: boolean) => {
|
|
1229
|
+
return this._submitExecutionTransactions(
|
|
1230
|
+
txs,
|
|
1231
|
+
abortSignal,
|
|
1232
|
+
[FromBTCSwapState.BTC_TX_CONFIRMED],
|
|
1233
|
+
idempotent
|
|
1234
|
+
);
|
|
1235
|
+
},
|
|
1236
|
+
requiredSigner: signerAddress ?? this._getInitiator()
|
|
1237
|
+
} as SwapExecutionActionSignSmartChainTx<T>;
|
|
837
1238
|
}
|
|
838
1239
|
|
|
839
1240
|
/**
|
|
@@ -849,33 +1250,66 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
849
1250
|
* @param options.maxWaitTillAutomaticSettlementSeconds Maximum time to wait for an automatic settlement after
|
|
850
1251
|
* the bitcoin transaction is confirmed (defaults to 60 seconds)
|
|
851
1252
|
*/
|
|
852
|
-
async
|
|
1253
|
+
async getExecutionAction(options?: {
|
|
853
1254
|
bitcoinFeeRate?: number,
|
|
854
1255
|
bitcoinWallet?: MinimalBitcoinWalletInterface,
|
|
855
1256
|
skipChecks?: boolean,
|
|
856
1257
|
manualSettlementSmartChainSigner?: string | T["Signer"] | T["NativeSigner"],
|
|
857
1258
|
maxWaitTillAutomaticSettlementSeconds?: number
|
|
858
|
-
}): Promise<
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1259
|
+
}): Promise<
|
|
1260
|
+
SwapExecutionActionSendToAddress<false> |
|
|
1261
|
+
SwapExecutionActionSignPSBT<"FUNDED_PSBT"> |
|
|
1262
|
+
SwapExecutionActionWait<"BITCOIN_CONFS" | "SETTLEMENT"> |
|
|
1263
|
+
SwapExecutionActionSignSmartChainTx<T> |
|
|
1264
|
+
undefined
|
|
1265
|
+
> {
|
|
1266
|
+
const executionStatus = await this._getExecutionStatus(options);
|
|
1267
|
+
return executionStatus.buildCurrentAction(options);
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/**
|
|
1271
|
+
* @inheritDoc
|
|
1272
|
+
*/
|
|
1273
|
+
async getExecutionStatus(options?: {
|
|
1274
|
+
skipBuildingAction?: boolean,
|
|
1275
|
+
bitcoinFeeRate?: number,
|
|
1276
|
+
bitcoinWallet?: MinimalBitcoinWalletInterface,
|
|
1277
|
+
skipChecks?: boolean,
|
|
1278
|
+
manualSettlementSmartChainSigner?: string | T["Signer"] | T["NativeSigner"],
|
|
1279
|
+
maxWaitTillAutomaticSettlementSeconds?: number
|
|
1280
|
+
}): Promise<{
|
|
1281
|
+
steps: [
|
|
1282
|
+
SwapExecutionStepSetup<T["ChainId"]>,
|
|
1283
|
+
SwapExecutionStepPayment<"BITCOIN">,
|
|
1284
|
+
SwapExecutionStepSettlement<T["ChainId"], "awaiting_automatic" | "awaiting_manual">
|
|
1285
|
+
],
|
|
1286
|
+
currentAction:
|
|
1287
|
+
SwapExecutionActionSendToAddress<false> |
|
|
1288
|
+
SwapExecutionActionSignPSBT<"FUNDED_PSBT"> |
|
|
1289
|
+
SwapExecutionActionWait<"BITCOIN_CONFS" | "SETTLEMENT"> |
|
|
1290
|
+
SwapExecutionActionSignSmartChainTx<T> |
|
|
1291
|
+
undefined,
|
|
1292
|
+
stateInfo: SwapStateInfo<FromBTCSwapState>
|
|
1293
|
+
}> {
|
|
1294
|
+
const executionStatus = await this._getExecutionStatus(options);
|
|
1295
|
+
return {
|
|
1296
|
+
steps: executionStatus.steps,
|
|
1297
|
+
currentAction: options?.skipBuildingAction ? undefined : await executionStatus.buildCurrentAction(options),
|
|
1298
|
+
stateInfo: this._getStateInfo(executionStatus.state)
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
/**
|
|
1303
|
+
* @inheritDoc
|
|
1304
|
+
*/
|
|
1305
|
+
async getExecutionSteps(options?: {
|
|
1306
|
+
maxWaitTillAutomaticSettlementSeconds?: number
|
|
1307
|
+
}): Promise<[
|
|
1308
|
+
SwapExecutionStepSetup<T["ChainId"]>,
|
|
1309
|
+
SwapExecutionStepPayment<"BITCOIN">,
|
|
1310
|
+
SwapExecutionStepSettlement<T["ChainId"], "awaiting_automatic" | "awaiting_manual">
|
|
1311
|
+
]> {
|
|
1312
|
+
return (await this._getExecutionStatus(options)).steps;
|
|
879
1313
|
}
|
|
880
1314
|
|
|
881
1315
|
//////////////////////////////
|
|
@@ -920,9 +1354,13 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
920
1354
|
]);
|
|
921
1355
|
abortController.abort();
|
|
922
1356
|
|
|
923
|
-
if(result===0)
|
|
924
|
-
|
|
925
|
-
if(result
|
|
1357
|
+
if(result===0) {
|
|
1358
|
+
this.logger.debug("waitTillCommited(): Resolved from state changed");
|
|
1359
|
+
} else if(result!=null) {
|
|
1360
|
+
this.logger.debug("waitTillCommited(): Resolved from watchdog - commited");
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
if(result===null) {
|
|
926
1364
|
this.logger.debug("waitTillCommited(): Resolved from watchdog - signature expired");
|
|
927
1365
|
if(this._state===FromBTCSwapState.PR_CREATED || this._state===FromBTCSwapState.QUOTE_SOFT_EXPIRED) {
|
|
928
1366
|
await this._saveAndEmit(FromBTCSwapState.QUOTE_EXPIRED);
|
|
@@ -931,6 +1369,8 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
931
1369
|
}
|
|
932
1370
|
|
|
933
1371
|
if(this._state===FromBTCSwapState.PR_CREATED || this._state===FromBTCSwapState.QUOTE_SOFT_EXPIRED) {
|
|
1372
|
+
if(typeof(result)==="object" && (result as any).getInitTxId!=null && this._commitTxId==null)
|
|
1373
|
+
this._commitTxId = await (result as any).getInitTxId();
|
|
934
1374
|
await this._saveAndEmit(FromBTCSwapState.CLAIM_COMMITED);
|
|
935
1375
|
}
|
|
936
1376
|
}
|
|
@@ -1045,7 +1485,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1045
1485
|
* @throws {Error} If swap is in invalid state (must be {@link FromBTCSwapState.BTC_TX_CONFIRMED})
|
|
1046
1486
|
* @throws {Error} If the LP refunded sooner than we were able to claim
|
|
1047
1487
|
*/
|
|
1048
|
-
async waitTillClaimed(maxWaitTimeSeconds?: number, abortSignal?: AbortSignal): Promise<boolean> {
|
|
1488
|
+
async waitTillClaimed(maxWaitTimeSeconds?: number, abortSignal?: AbortSignal, pollIntervalSeconds?: number): Promise<boolean> {
|
|
1049
1489
|
if(this._state===FromBTCSwapState.CLAIM_CLAIMED) return Promise.resolve(true);
|
|
1050
1490
|
if(this._state!==FromBTCSwapState.BTC_TX_CONFIRMED) throw new Error("Invalid state (not BTC_TX_CONFIRMED)");
|
|
1051
1491
|
|
|
@@ -1063,7 +1503,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1063
1503
|
let res: 0 | 1 | SwapCommitState;
|
|
1064
1504
|
try {
|
|
1065
1505
|
res = await Promise.race([
|
|
1066
|
-
this.watchdogWaitTillResult(
|
|
1506
|
+
this.watchdogWaitTillResult(pollIntervalSeconds, abortController.signal),
|
|
1067
1507
|
this.waitTillState(FromBTCSwapState.CLAIM_CLAIMED, "eq", abortController.signal).then(() => 0 as const),
|
|
1068
1508
|
this.waitTillState(FromBTCSwapState.FAILED, "eq", abortController.signal).then(() => 1 as const),
|
|
1069
1509
|
]);
|
|
@@ -1200,24 +1640,38 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1200
1640
|
async _forciblySetOnchainState(status: SwapCommitState): Promise<boolean> {
|
|
1201
1641
|
switch(status.type) {
|
|
1202
1642
|
case SwapCommitStateType.PAID:
|
|
1643
|
+
if(this._commitTxId==null && (status as any).getInitTxId!=null) this._commitTxId = await (status as any).getInitTxId();
|
|
1203
1644
|
if(this._claimTxId==null) this._claimTxId = await status.getClaimTxId();
|
|
1204
1645
|
const txId = Buffer.from(await status.getClaimResult(), "hex").reverse().toString("hex");
|
|
1205
1646
|
await this._setBitcoinTxId(txId);
|
|
1206
1647
|
this._state = FromBTCSwapState.CLAIM_CLAIMED;
|
|
1207
1648
|
return true;
|
|
1208
1649
|
case SwapCommitStateType.NOT_COMMITED:
|
|
1209
|
-
|
|
1650
|
+
let changed: boolean = false;
|
|
1651
|
+
if(this._commitTxId==null && (status as any).getInitTxId!=null) {
|
|
1652
|
+
this._commitTxId = await (status as any).getInitTxId();
|
|
1653
|
+
changed = true;
|
|
1654
|
+
}
|
|
1655
|
+
if(this._refundTxId==null && status.getRefundTxId) {
|
|
1656
|
+
this._refundTxId = await status.getRefundTxId();
|
|
1657
|
+
changed = true;
|
|
1658
|
+
}
|
|
1210
1659
|
if(this._refundTxId!=null) {
|
|
1211
1660
|
this._state = FromBTCSwapState.FAILED;
|
|
1212
|
-
|
|
1661
|
+
changed = true;
|
|
1213
1662
|
}
|
|
1214
|
-
|
|
1663
|
+
return changed;
|
|
1215
1664
|
case SwapCommitStateType.EXPIRED:
|
|
1665
|
+
if(this._commitTxId==null && (status as any).getInitTxId!=null) this._commitTxId = await (status as any).getInitTxId();
|
|
1216
1666
|
if(this._refundTxId==null && status.getRefundTxId) this._refundTxId = await status.getRefundTxId();
|
|
1217
1667
|
this._state = this._refundTxId==null ? FromBTCSwapState.QUOTE_EXPIRED : FromBTCSwapState.FAILED;
|
|
1218
1668
|
return true;
|
|
1219
1669
|
case SwapCommitStateType.COMMITED:
|
|
1220
1670
|
let save: boolean = false;
|
|
1671
|
+
if(this._commitTxId==null && (status as any).getInitTxId!=null) {
|
|
1672
|
+
this._commitTxId = await (status as any).getInitTxId();
|
|
1673
|
+
save = true;
|
|
1674
|
+
}
|
|
1221
1675
|
if(this._state!==FromBTCSwapState.CLAIM_COMMITED && this._state!==FromBTCSwapState.BTC_TX_CONFIRMED && this._state!==FromBTCSwapState.EXPIRED) {
|
|
1222
1676
|
this._state = FromBTCSwapState.CLAIM_COMMITED;
|
|
1223
1677
|
save = true;
|
|
@@ -1227,7 +1681,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1227
1681
|
this.btcTxLastChecked = Date.now();
|
|
1228
1682
|
const res = await this.getBitcoinPayment();
|
|
1229
1683
|
if(res!=null) {
|
|
1230
|
-
if(this.txId!==res.txId) {
|
|
1684
|
+
if(this.txId!==res.txId || this.vout!==res.vout || (res.inputAddresses!=null && this.senderAddress==null)) {
|
|
1231
1685
|
if(res.inputAddresses!=null) this.senderAddress = res.inputAddresses[0];
|
|
1232
1686
|
this.txId = res.txId;
|
|
1233
1687
|
this.vout = res.vout;
|
|
@@ -1271,7 +1725,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1271
1725
|
const res = await this.getBitcoinPayment();
|
|
1272
1726
|
if(res!=null) {
|
|
1273
1727
|
let shouldSave: boolean = false;
|
|
1274
|
-
if(this.txId!==res.txId) {
|
|
1728
|
+
if(this.txId!==res.txId || this.vout!==res.vout || (res.inputAddresses!=null && this.senderAddress==null)) {
|
|
1275
1729
|
this.txId = res.txId;
|
|
1276
1730
|
this.vout = res.vout;
|
|
1277
1731
|
if(res.inputAddresses!=null) this.senderAddress = res.inputAddresses[0];
|