@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
|
@@ -150,6 +150,7 @@ export class FromBTCWrapper<
|
|
|
150
150
|
* @param versionedContracts
|
|
151
151
|
* @param versionedSynchronizer
|
|
152
152
|
* @param btcRpc Bitcoin RPC which also supports getting transactions by txoHash
|
|
153
|
+
* @param lpApi
|
|
153
154
|
* @param options
|
|
154
155
|
* @param events Instance to use for emitting events
|
|
155
156
|
*/
|
|
@@ -173,11 +174,12 @@ export class FromBTCWrapper<
|
|
|
173
174
|
}
|
|
174
175
|
},
|
|
175
176
|
btcRpc: BitcoinRpcWithAddressIndex<any>,
|
|
177
|
+
lpApi: IntermediaryAPI,
|
|
176
178
|
options?: AllOptional<FromBTCWrapperOptions>,
|
|
177
179
|
events?: EventEmitter<{swapState: [ISwap]}>
|
|
178
180
|
) {
|
|
179
181
|
super(
|
|
180
|
-
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens,
|
|
182
|
+
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, lpApi,
|
|
181
183
|
{
|
|
182
184
|
...options,
|
|
183
185
|
bitcoinNetwork: options?.bitcoinNetwork ?? TEST_NETWORK,
|
|
@@ -497,7 +499,7 @@ export class FromBTCWrapper<
|
|
|
497
499
|
|
|
498
500
|
try {
|
|
499
501
|
const {signDataPromise, resp} = await tryWithRetries(async(retryCount: number) => {
|
|
500
|
-
const {signDataPrefetch, response} =
|
|
502
|
+
const {signDataPrefetch, response} = this._lpApi.initFromBTC(
|
|
501
503
|
this.chainIdentifier, lp.url, nativeTokenAddress,
|
|
502
504
|
{
|
|
503
505
|
claimer: recipient,
|
|
@@ -507,8 +509,8 @@ export class FromBTCWrapper<
|
|
|
507
509
|
exactOut: !amountData.exactIn,
|
|
508
510
|
sequence,
|
|
509
511
|
|
|
510
|
-
claimerBounty: throwIfUndefined(claimerBountyPrefetchPromise[version]),
|
|
511
|
-
feeRate: throwIfUndefined(feeRatePromise[version]),
|
|
512
|
+
claimerBounty: throwIfUndefined(claimerBountyPrefetchPromise[version], "Watchtower fee pre-fetch failed!"),
|
|
513
|
+
feeRate: throwIfUndefined(feeRatePromise[version], "Network fee rate pre-fetch failed!"),
|
|
512
514
|
additionalParams
|
|
513
515
|
},
|
|
514
516
|
this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined
|
|
@@ -538,7 +540,7 @@ export class FromBTCWrapper<
|
|
|
538
540
|
amountData.token, {swapFeeBtc}, pricePrefetchPromise, usdPricePrefetchPromise, abortController.signal
|
|
539
541
|
),
|
|
540
542
|
this.verifyReturnedSignature(recipient, data, resp, feeRatePromise[version], signDataPromise, version, abortController.signal),
|
|
541
|
-
this.verifyIntermediaryLiquidity(data.getAmount(), throwIfUndefined(liquidityPromise)),
|
|
543
|
+
this.verifyIntermediaryLiquidity(data.getAmount(), throwIfUndefined(liquidityPromise, "LP liquidity pre-fetch failed!")),
|
|
542
544
|
]);
|
|
543
545
|
|
|
544
546
|
const quote = new FromBTCSwap<T>(this, {
|
|
@@ -23,7 +23,14 @@ import {ppmToPercentage} from "../../../types/fees/PercentagePPM";
|
|
|
23
23
|
import {TokenAmount, toTokenAmount} from "../../../types/TokenAmount";
|
|
24
24
|
import {BtcToken, SCToken} from "../../../types/Token";
|
|
25
25
|
import {timeoutPromise} from "../../../utils/TimeoutUtils";
|
|
26
|
-
import {
|
|
26
|
+
import {SwapExecutionActionSignSmartChainTx, SwapExecutionActionWait} from "../../../types/SwapExecutionAction";
|
|
27
|
+
import {
|
|
28
|
+
SwapExecutionStep,
|
|
29
|
+
SwapExecutionStepPayment,
|
|
30
|
+
SwapExecutionStepRefund,
|
|
31
|
+
SwapExecutionStepSettlement
|
|
32
|
+
} from "../../../types/SwapExecutionStep";
|
|
33
|
+
import {SwapStateInfo} from "../../../types/SwapStateInfo";
|
|
27
34
|
|
|
28
35
|
export type IToBTCSwapInit<T extends SwapData> = IEscrowSelfInitSwapInit<T> & {
|
|
29
36
|
signatureData?: SignatureData,
|
|
@@ -534,27 +541,199 @@ export abstract class IToBTCSwap<
|
|
|
534
541
|
throw new Error("Unexpected state reached!");
|
|
535
542
|
}
|
|
536
543
|
|
|
544
|
+
/**
|
|
545
|
+
* @internal
|
|
546
|
+
*/
|
|
547
|
+
protected async _getExecutionStatus() {
|
|
548
|
+
const state = this._state;
|
|
549
|
+
|
|
550
|
+
let sourcePaymentStatus: SwapExecutionStepPayment<T["ChainId"]>["status"] = "inactive";
|
|
551
|
+
let destinationPayoutStatus: SwapExecutionStepSettlement<"BITCOIN" | "LIGHTNING", "soft_settled">["status"] = "inactive";
|
|
552
|
+
let refundStatus: SwapExecutionStepRefund<T["ChainId"]>["status"] = "inactive";
|
|
553
|
+
let buildCurrentAction: (actionOptions?: {
|
|
554
|
+
skipChecks?: boolean,
|
|
555
|
+
refundSmartChainSigner?: string | T["Signer"] | T["NativeSigner"]
|
|
556
|
+
}) => Promise<
|
|
557
|
+
SwapExecutionActionSignSmartChainTx<T> |
|
|
558
|
+
SwapExecutionActionWait<"LP"> |
|
|
559
|
+
undefined
|
|
560
|
+
> = async () => undefined;
|
|
561
|
+
|
|
562
|
+
switch(state) {
|
|
563
|
+
case ToBTCSwapState.CREATED:
|
|
564
|
+
const quoteValid = await this._verifyQuoteValid();
|
|
565
|
+
sourcePaymentStatus = quoteValid ? "awaiting" : "soft_expired";
|
|
566
|
+
if(this.signatureData!=null && quoteValid) {
|
|
567
|
+
buildCurrentAction = this._buildInitSmartChainTxAction.bind(this);
|
|
568
|
+
}
|
|
569
|
+
break;
|
|
570
|
+
case ToBTCSwapState.QUOTE_SOFT_EXPIRED:
|
|
571
|
+
sourcePaymentStatus = "soft_expired";
|
|
572
|
+
break;
|
|
573
|
+
case ToBTCSwapState.QUOTE_EXPIRED:
|
|
574
|
+
sourcePaymentStatus = "expired";
|
|
575
|
+
break;
|
|
576
|
+
case ToBTCSwapState.COMMITED:
|
|
577
|
+
sourcePaymentStatus = "confirmed";
|
|
578
|
+
destinationPayoutStatus = "waiting_lp";
|
|
579
|
+
buildCurrentAction = this._buildWaitLpAction.bind(this);
|
|
580
|
+
break;
|
|
581
|
+
case ToBTCSwapState.SOFT_CLAIMED:
|
|
582
|
+
sourcePaymentStatus = "confirmed";
|
|
583
|
+
destinationPayoutStatus = "soft_settled";
|
|
584
|
+
break;
|
|
585
|
+
case ToBTCSwapState.CLAIMED:
|
|
586
|
+
sourcePaymentStatus = "confirmed";
|
|
587
|
+
destinationPayoutStatus = "settled";
|
|
588
|
+
break;
|
|
589
|
+
case ToBTCSwapState.REFUNDABLE:
|
|
590
|
+
sourcePaymentStatus = "confirmed";
|
|
591
|
+
destinationPayoutStatus = "expired";
|
|
592
|
+
refundStatus = "awaiting";
|
|
593
|
+
buildCurrentAction = this._buildRefundSmartChainTxAction.bind(this);
|
|
594
|
+
break;
|
|
595
|
+
case ToBTCSwapState.REFUNDED:
|
|
596
|
+
sourcePaymentStatus = "confirmed";
|
|
597
|
+
destinationPayoutStatus = "expired";
|
|
598
|
+
refundStatus = "refunded";
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
return {
|
|
603
|
+
steps: [
|
|
604
|
+
{
|
|
605
|
+
type: "Payment",
|
|
606
|
+
side: "source",
|
|
607
|
+
chain: this.chainIdentifier,
|
|
608
|
+
title: "Source payment",
|
|
609
|
+
description: `Initiate the swap by funding the escrow on the ${this.chainIdentifier} side`,
|
|
610
|
+
status: sourcePaymentStatus,
|
|
611
|
+
initTxId: this._commitTxId,
|
|
612
|
+
settleTxId: this._claimTxId
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
type: "Settlement",
|
|
616
|
+
side: "destination",
|
|
617
|
+
chain: this.outputToken.chainId,
|
|
618
|
+
title: "Destination payout",
|
|
619
|
+
description: `Wait for the LP to process the swap and send the payout on the ${this.outputToken.chainId} side`,
|
|
620
|
+
status: destinationPayoutStatus,
|
|
621
|
+
initTxId: destinationPayoutStatus==="settled" || destinationPayoutStatus==="soft_settled" ? this.getOutputTxId() : undefined,
|
|
622
|
+
settleTxId: destinationPayoutStatus==="settled" ? this.getOutputTxId() : undefined,
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
type: "Refund",
|
|
626
|
+
side: "source",
|
|
627
|
+
chain: this.chainIdentifier,
|
|
628
|
+
title: "Source refund",
|
|
629
|
+
description: `Refund escrowed funds on the ${this.chainIdentifier} side, after LP failed to execute`,
|
|
630
|
+
status: refundStatus,
|
|
631
|
+
refundTxId: this._refundTxId
|
|
632
|
+
}
|
|
633
|
+
] as [
|
|
634
|
+
SwapExecutionStepPayment<T["ChainId"]>,
|
|
635
|
+
SwapExecutionStepSettlement<"BITCOIN" | "LIGHTNING", "soft_settled">,
|
|
636
|
+
SwapExecutionStepRefund<T["ChainId"]>,
|
|
637
|
+
],
|
|
638
|
+
buildCurrentAction,
|
|
639
|
+
state
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
|
|
537
643
|
/**
|
|
538
644
|
* @inheritDoc
|
|
539
|
-
*
|
|
540
|
-
* @param options.skipChecks Skip checks like making sure init signature is still valid and swap wasn't commited yet
|
|
541
|
-
* (this is handled on swap creation, if you commit right after quoting, you can use `skipChecks=true`)
|
|
645
|
+
* @internal
|
|
542
646
|
*/
|
|
543
|
-
async
|
|
647
|
+
async _submitExecutionTransactions(txs: (T["SignedTXType"] | string)[], abortSignal?: AbortSignal, requiredStates?: ToBTCSwapState[], idempotent?: boolean): Promise<string[]> {
|
|
648
|
+
const parsedTxs: T["SignedTXType"][] = [];
|
|
649
|
+
for(let tx of txs) {
|
|
650
|
+
parsedTxs.push(typeof(tx)==="string" ? await this.wrapper._chain.deserializeSignedTx(tx) : tx);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
if(idempotent) {
|
|
654
|
+
// Handle idempotent calls
|
|
655
|
+
if(this.wrapper._chain.getTxId!=null) {
|
|
656
|
+
const txIds = await Promise.all(parsedTxs.map(tx => this.wrapper._chain.getTxId!(tx)));
|
|
657
|
+
const foundTxId = txIds.find(txId => this._commitTxId===txId || this._refundTxId===txId);
|
|
658
|
+
if(foundTxId!=null) return txIds;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if(requiredStates!=null && !requiredStates.includes(this._state)) throw new Error("Swap state has changed before transactions were submitted!");
|
|
663
|
+
|
|
664
|
+
if(this._state===ToBTCSwapState.CREATED || this._state===ToBTCSwapState.QUOTE_SOFT_EXPIRED) {
|
|
665
|
+
if(!await this._verifyQuoteValid()) throw new Error("Quote is already expired!");
|
|
666
|
+
const txIds = await this.wrapper._chain.sendSignedAndConfirm(parsedTxs, true, abortSignal, false);
|
|
667
|
+
await this.waitTillCommited(abortSignal);
|
|
668
|
+
return txIds;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
if(this._state===ToBTCSwapState.REFUNDABLE) {
|
|
672
|
+
const txIds = await this.wrapper._chain.sendSignedAndConfirm(parsedTxs, true, abortSignal, false);
|
|
673
|
+
await this.waitTillRefunded(abortSignal);
|
|
674
|
+
return txIds;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
throw new Error("Invalid swap state for transaction submission!");
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* @internal
|
|
682
|
+
*/
|
|
683
|
+
private async _buildInitSmartChainTxAction(actionOptions?: {
|
|
544
684
|
skipChecks?: boolean
|
|
545
|
-
}): Promise<
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
685
|
+
}): Promise<SwapExecutionActionSignSmartChainTx> {
|
|
686
|
+
return {
|
|
687
|
+
type: "SignSmartChainTransaction",
|
|
688
|
+
name: "Initiate swap",
|
|
689
|
+
description: `Initiates the swap by commiting the funds to the escrow on the ${this.chainIdentifier} side`,
|
|
690
|
+
chain: this.chainIdentifier,
|
|
691
|
+
txs: await this.prepareTransactions(this.txsCommit(actionOptions?.skipChecks)),
|
|
692
|
+
submitTransactions: async (txs: (T["SignedTXType"] | string)[], abortSignal?: AbortSignal, idempotent?: boolean) => {
|
|
693
|
+
return this._submitExecutionTransactions(txs, abortSignal, [ToBTCSwapState.CREATED, ToBTCSwapState.QUOTE_SOFT_EXPIRED], idempotent);
|
|
694
|
+
},
|
|
695
|
+
requiredSigner: this._getInitiator()
|
|
696
|
+
} as SwapExecutionActionSignSmartChainTx;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* @internal
|
|
701
|
+
*/
|
|
702
|
+
private async _buildWaitLpAction(): Promise<SwapExecutionActionWait<"LP">> {
|
|
703
|
+
return {
|
|
704
|
+
type: "Wait",
|
|
705
|
+
name: "Awaiting LP payout",
|
|
706
|
+
description: "Wait for the intermediary to process the swap and either send the payout or make the swap refundable",
|
|
707
|
+
pollTimeSeconds: 5,
|
|
708
|
+
expectedTimeSeconds: 10,
|
|
709
|
+
wait: async (
|
|
710
|
+
maxWaitTimeSeconds?: number, pollIntervalSeconds?: number, abortSignal?: AbortSignal
|
|
711
|
+
) => {
|
|
712
|
+
await this.waitForPayment(maxWaitTimeSeconds, pollIntervalSeconds, abortSignal);
|
|
556
713
|
}
|
|
557
|
-
|
|
714
|
+
} as SwapExecutionActionWait<"LP">;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* @internal
|
|
719
|
+
*/
|
|
720
|
+
private async _buildRefundSmartChainTxAction(actionOptions?: {
|
|
721
|
+
refundSmartChainSigner?: string | T["Signer"] | T["NativeSigner"]
|
|
722
|
+
}): Promise<SwapExecutionActionSignSmartChainTx> {
|
|
723
|
+
const signerAddress =
|
|
724
|
+
await this.wrapper._getSignerAddress(actionOptions?.refundSmartChainSigner);
|
|
725
|
+
|
|
726
|
+
return {
|
|
727
|
+
type: "SignSmartChainTransaction",
|
|
728
|
+
name: "Refund",
|
|
729
|
+
description: "Refund the swap after it failed to execute",
|
|
730
|
+
chain: this.chainIdentifier,
|
|
731
|
+
txs: await this.prepareTransactions(this.txsRefund(actionOptions?.refundSmartChainSigner)),
|
|
732
|
+
submitTransactions: async (txs: (T["SignedTXType"] | string)[], abortSignal?: AbortSignal, idempotent?: boolean) => {
|
|
733
|
+
return this._submitExecutionTransactions(txs, abortSignal, [ToBTCSwapState.REFUNDABLE], idempotent);
|
|
734
|
+
},
|
|
735
|
+
requiredSigner: signerAddress ?? this._getInitiator()
|
|
736
|
+
} as SwapExecutionActionSignSmartChainTx;
|
|
558
737
|
}
|
|
559
738
|
|
|
560
739
|
/**
|
|
@@ -564,24 +743,54 @@ export abstract class IToBTCSwap<
|
|
|
564
743
|
* (this is handled on swap creation, if you commit right after quoting, you can use `skipChecks=true`)
|
|
565
744
|
* @param options.refundSmartChainSigner Optional smart chain signer to use when creating refunds transactions
|
|
566
745
|
*/
|
|
567
|
-
async
|
|
746
|
+
async getExecutionAction(options?: {
|
|
568
747
|
skipChecks?: boolean,
|
|
569
748
|
refundSmartChainSigner?: string | T["Signer"] | T["NativeSigner"]
|
|
570
|
-
}): Promise<
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
749
|
+
}): Promise<
|
|
750
|
+
SwapExecutionActionSignSmartChainTx<T> |
|
|
751
|
+
SwapExecutionActionWait<"LP"> |
|
|
752
|
+
undefined
|
|
753
|
+
> {
|
|
754
|
+
const executionStatus = await this._getExecutionStatus();
|
|
755
|
+
return executionStatus.buildCurrentAction(options);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* @inheritDoc
|
|
760
|
+
*/
|
|
761
|
+
async getExecutionStatus(options?: {
|
|
762
|
+
skipBuildingAction?: boolean,
|
|
763
|
+
skipChecks?: boolean,
|
|
764
|
+
refundSmartChainSigner?: string | T["Signer"] | T["NativeSigner"]
|
|
765
|
+
}): Promise<{
|
|
766
|
+
steps: [
|
|
767
|
+
SwapExecutionStepPayment<T["ChainId"]>,
|
|
768
|
+
SwapExecutionStepSettlement<"BITCOIN" | "LIGHTNING", "soft_settled">,
|
|
769
|
+
SwapExecutionStepRefund<T["ChainId"]>,
|
|
770
|
+
],
|
|
771
|
+
currentAction:
|
|
772
|
+
SwapExecutionActionSignSmartChainTx<T> |
|
|
773
|
+
SwapExecutionActionWait<"LP"> |
|
|
774
|
+
undefined,
|
|
775
|
+
stateInfo: SwapStateInfo<ToBTCSwapState>
|
|
776
|
+
}> {
|
|
777
|
+
const executionStatus = await this._getExecutionStatus();
|
|
778
|
+
return {
|
|
779
|
+
steps: executionStatus.steps,
|
|
780
|
+
currentAction: options?.skipBuildingAction ? undefined : await executionStatus.buildCurrentAction(options),
|
|
781
|
+
stateInfo: this._getStateInfo(executionStatus.state)
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* @inheritDoc
|
|
787
|
+
*/
|
|
788
|
+
async getExecutionSteps(): Promise<[
|
|
789
|
+
SwapExecutionStepPayment<T["ChainId"]>,
|
|
790
|
+
SwapExecutionStepSettlement<"BITCOIN" | "LIGHTNING", "soft_settled">,
|
|
791
|
+
SwapExecutionStepRefund<T["ChainId"]>,
|
|
792
|
+
]> {
|
|
793
|
+
return (await this._getExecutionStatus()).steps;
|
|
585
794
|
}
|
|
586
795
|
|
|
587
796
|
//////////////////////////////
|
|
@@ -641,7 +850,7 @@ export abstract class IToBTCSwap<
|
|
|
641
850
|
if(this._state!==ToBTCSwapState.CREATED && this._state!==ToBTCSwapState.QUOTE_SOFT_EXPIRED) throw new Error("Invalid state (not CREATED)");
|
|
642
851
|
|
|
643
852
|
const abortController = extendAbortController(abortSignal);
|
|
644
|
-
let result: number |
|
|
853
|
+
let result: SwapCommitState | number | null;
|
|
645
854
|
try {
|
|
646
855
|
result = await Promise.race([
|
|
647
856
|
this.watchdogWaitTillCommited(undefined, abortController.signal),
|
|
@@ -653,9 +862,13 @@ export abstract class IToBTCSwap<
|
|
|
653
862
|
throw e;
|
|
654
863
|
}
|
|
655
864
|
|
|
656
|
-
if(result===0)
|
|
657
|
-
|
|
658
|
-
if(result
|
|
865
|
+
if(result===0) {
|
|
866
|
+
this.logger.debug("waitTillCommited(): Resolved from state change");
|
|
867
|
+
} else if(result!=null) {
|
|
868
|
+
this.logger.debug("waitTillCommited(): Resolved from watchdog - commited");
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
if(result===null) {
|
|
659
872
|
this.logger.debug("waitTillCommited(): Resolved from watchdog - signature expiry");
|
|
660
873
|
if(this._state===ToBTCSwapState.QUOTE_SOFT_EXPIRED || this._state===ToBTCSwapState.CREATED) {
|
|
661
874
|
await this._saveAndEmit(ToBTCSwapState.QUOTE_EXPIRED);
|
|
@@ -664,6 +877,8 @@ export abstract class IToBTCSwap<
|
|
|
664
877
|
}
|
|
665
878
|
|
|
666
879
|
if(this._state===ToBTCSwapState.QUOTE_SOFT_EXPIRED || this._state===ToBTCSwapState.CREATED || this._state===ToBTCSwapState.QUOTE_EXPIRED) {
|
|
880
|
+
if(typeof(result)==="object" && (result as any).getInitTxId!=null && this._commitTxId==null)
|
|
881
|
+
this._commitTxId = await (result as any).getInitTxId();
|
|
667
882
|
await this._saveAndEmit(ToBTCSwapState.COMMITED);
|
|
668
883
|
}
|
|
669
884
|
}
|
|
@@ -689,7 +904,7 @@ export abstract class IToBTCSwap<
|
|
|
689
904
|
while(!abortSignal?.aborted && (
|
|
690
905
|
resp.code===RefundAuthorizationResponseCodes.PENDING || resp.code===RefundAuthorizationResponseCodes.NOT_FOUND
|
|
691
906
|
)) {
|
|
692
|
-
resp = await
|
|
907
|
+
resp = await this.wrapper._lpApi.getRefundAuthorization(this.url, this.getLpIdentifier(), this._data.getSequence());
|
|
693
908
|
if(resp.code===RefundAuthorizationResponseCodes.PAID) {
|
|
694
909
|
const validResponse = await this._setPaymentResult(resp.data, true);
|
|
695
910
|
if(validResponse) {
|
|
@@ -722,7 +937,7 @@ export abstract class IToBTCSwap<
|
|
|
722
937
|
if(this._state===ToBTCSwapState.CREATED || this._state==ToBTCSwapState.QUOTE_EXPIRED || this.url==null) return false;
|
|
723
938
|
if(this.isFinished() || this.isRefundable()) return true;
|
|
724
939
|
//Check if that maybe already concluded according to the LP
|
|
725
|
-
const resp = await
|
|
940
|
+
const resp = await this.wrapper._lpApi.getRefundAuthorization(this.url, this.getLpIdentifier(), this._data.getSequence());
|
|
726
941
|
switch(resp.code) {
|
|
727
942
|
case RefundAuthorizationResponseCodes.PAID:
|
|
728
943
|
const processed = await this._setPaymentResult(resp.data, true);
|
|
@@ -859,7 +1074,7 @@ export abstract class IToBTCSwap<
|
|
|
859
1074
|
return await this._contract.txsRefund(signer, this._data, true, true);
|
|
860
1075
|
} else {
|
|
861
1076
|
if(this.url==null) throw new Error("LP URL not known, cannot get cooperative refund message, wait till expiry to refund!");
|
|
862
|
-
const res = await
|
|
1077
|
+
const res = await this.wrapper._lpApi.getRefundAuthorization(this.url, this.getLpIdentifier(), this._data.getSequence());
|
|
863
1078
|
if(res.code===RefundAuthorizationResponseCodes.REFUND_DATA) {
|
|
864
1079
|
return await this._contract.txsRefundWithAuthorization(
|
|
865
1080
|
signer,
|
|
@@ -1035,6 +1250,7 @@ export abstract class IToBTCSwap<
|
|
|
1035
1250
|
async _forciblySetOnchainState(commitStatus: SwapCommitState): Promise<boolean> {
|
|
1036
1251
|
switch(commitStatus.type) {
|
|
1037
1252
|
case SwapCommitStateType.PAID:
|
|
1253
|
+
if(this._commitTxId==null && (commitStatus as any).getInitTxId!=null) this._commitTxId = await (commitStatus as any).getInitTxId();
|
|
1038
1254
|
if(this._claimTxId==null && commitStatus.getClaimTxId) this._claimTxId = await commitStatus.getClaimTxId();
|
|
1039
1255
|
const eventResult = await commitStatus.getClaimResult();
|
|
1040
1256
|
try {
|
|
@@ -1045,25 +1261,40 @@ export abstract class IToBTCSwap<
|
|
|
1045
1261
|
this._state = ToBTCSwapState.CLAIMED;
|
|
1046
1262
|
return true;
|
|
1047
1263
|
case SwapCommitStateType.REFUNDABLE:
|
|
1264
|
+
if(this._commitTxId==null && (commitStatus as any).getInitTxId!=null) this._commitTxId = await (commitStatus as any).getInitTxId();
|
|
1048
1265
|
this._state = ToBTCSwapState.REFUNDABLE;
|
|
1049
1266
|
return true;
|
|
1050
1267
|
case SwapCommitStateType.EXPIRED:
|
|
1268
|
+
if(this._commitTxId==null && (commitStatus as any).getInitTxId!=null) this._commitTxId = await (commitStatus as any).getInitTxId();
|
|
1051
1269
|
if(this._refundTxId==null && commitStatus.getRefundTxId) this._refundTxId = await commitStatus.getRefundTxId();
|
|
1052
1270
|
this._state = this._refundTxId==null ? ToBTCSwapState.QUOTE_EXPIRED : ToBTCSwapState.REFUNDED;
|
|
1053
1271
|
return true;
|
|
1054
1272
|
case SwapCommitStateType.NOT_COMMITED:
|
|
1055
|
-
|
|
1273
|
+
let changed: boolean = false;
|
|
1274
|
+
if(this._commitTxId==null && (commitStatus as any).getInitTxId!=null) {
|
|
1275
|
+
this._commitTxId = await (commitStatus as any).getInitTxId();
|
|
1276
|
+
changed = true;
|
|
1277
|
+
}
|
|
1278
|
+
if(this._refundTxId==null && commitStatus.getRefundTxId) {
|
|
1279
|
+
this._refundTxId = await commitStatus.getRefundTxId();
|
|
1280
|
+
changed = true;
|
|
1281
|
+
}
|
|
1056
1282
|
if(this._refundTxId!=null) {
|
|
1057
1283
|
this._state = ToBTCSwapState.REFUNDED;
|
|
1058
|
-
|
|
1284
|
+
changed = true;
|
|
1059
1285
|
}
|
|
1060
|
-
|
|
1286
|
+
return changed;
|
|
1061
1287
|
case SwapCommitStateType.COMMITED:
|
|
1288
|
+
let save: boolean = false;
|
|
1289
|
+
if(this._commitTxId==null && (commitStatus as any).getInitTxId!=null) {
|
|
1290
|
+
this._commitTxId = await (commitStatus as any).getInitTxId();
|
|
1291
|
+
save = true;
|
|
1292
|
+
}
|
|
1062
1293
|
if(this._state!==ToBTCSwapState.COMMITED && this._state!==ToBTCSwapState.REFUNDABLE && this._state!==ToBTCSwapState.SOFT_CLAIMED) {
|
|
1063
1294
|
this._state = ToBTCSwapState.COMMITED;
|
|
1064
|
-
|
|
1295
|
+
save = true;
|
|
1065
1296
|
}
|
|
1066
|
-
|
|
1297
|
+
return save;
|
|
1067
1298
|
}
|
|
1068
1299
|
return false;
|
|
1069
1300
|
}
|
|
@@ -110,11 +110,12 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
110
110
|
swapDataConstructor: new (data: any) => T["Data"]
|
|
111
111
|
}
|
|
112
112
|
},
|
|
113
|
+
lpApi: IntermediaryAPI,
|
|
113
114
|
options?: AllOptional<ToBTCLNWrapperOptions>,
|
|
114
115
|
events?: EventEmitter<{swapState: [ISwap]}>
|
|
115
116
|
) {
|
|
116
117
|
super(
|
|
117
|
-
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens,
|
|
118
|
+
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, lpApi,
|
|
118
119
|
{
|
|
119
120
|
...options,
|
|
120
121
|
paymentTimeoutSeconds: options?.paymentTimeoutSeconds ?? 5*24*60*60,
|
|
@@ -286,13 +287,13 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
286
287
|
|
|
287
288
|
try {
|
|
288
289
|
const {signDataPromise, resp} = await tryWithRetries(async(retryCount: number) => {
|
|
289
|
-
const {signDataPrefetch, response} =
|
|
290
|
+
const {signDataPrefetch, response} = this._lpApi.initToBTCLN(this.chainIdentifier, lp.url, {
|
|
290
291
|
offerer: signer,
|
|
291
292
|
pr,
|
|
292
293
|
maxFee: await calculatedOptions.maxFee,
|
|
293
294
|
expiryTimestamp: calculatedOptions.expiryTimestamp,
|
|
294
295
|
token: amountData.token,
|
|
295
|
-
feeRate: throwIfUndefined(preFetches.feeRatePromise[version]),
|
|
296
|
+
feeRate: throwIfUndefined(preFetches.feeRatePromise[version], "Network fee rate pre-fetch failed!"),
|
|
296
297
|
additionalParams
|
|
297
298
|
}, this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined);
|
|
298
299
|
|
|
@@ -481,7 +482,7 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
481
482
|
|
|
482
483
|
try {
|
|
483
484
|
const {signDataPromise, prepareResp} = await tryWithRetries(async(retryCount: number) => {
|
|
484
|
-
const {signDataPrefetch, response} =
|
|
485
|
+
const {signDataPrefetch, response} = this._lpApi.prepareToBTCLNExactIn(this.chainIdentifier, lp.url, {
|
|
485
486
|
token: amountData.token,
|
|
486
487
|
offerer: signer,
|
|
487
488
|
pr: dummyPr,
|
|
@@ -511,10 +512,10 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
511
512
|
const parsedInvoice = bolt11Decode(invoice);
|
|
512
513
|
|
|
513
514
|
const resp = await tryWithRetries(
|
|
514
|
-
(retryCount: number) =>
|
|
515
|
+
(retryCount: number) => this._lpApi.initToBTCLNExactIn(lp.url, {
|
|
515
516
|
pr: invoice,
|
|
516
517
|
reqId: prepareResp.reqId,
|
|
517
|
-
feeRate: throwIfUndefined(preFetches.feeRatePromise[version]),
|
|
518
|
+
feeRate: throwIfUndefined(preFetches.feeRatePromise[version], "Network fee rate pre-fetch failed!"),
|
|
518
519
|
additionalParams
|
|
519
520
|
}, this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined),
|
|
520
521
|
undefined, RequestError, abortController.signal
|
|
@@ -82,6 +82,7 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
|
|
|
82
82
|
* @param prices Swap pricing handler
|
|
83
83
|
* @param tokens
|
|
84
84
|
* @param btcRpc Bitcoin RPC api
|
|
85
|
+
* @param lpApi
|
|
85
86
|
* @param options
|
|
86
87
|
* @param events Instance to use for emitting events
|
|
87
88
|
*/
|
|
@@ -99,11 +100,12 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
|
|
|
99
100
|
}
|
|
100
101
|
},
|
|
101
102
|
btcRpc: BitcoinRpc<any>,
|
|
103
|
+
lpApi: IntermediaryAPI,
|
|
102
104
|
options?: AllOptional<ToBTCWrapperOptions>,
|
|
103
105
|
events?: EventEmitter<{swapState: [ISwap]}>
|
|
104
106
|
) {
|
|
105
107
|
super(
|
|
106
|
-
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens,
|
|
108
|
+
chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, lpApi,
|
|
107
109
|
{
|
|
108
110
|
...options,
|
|
109
111
|
bitcoinNetwork: options?.bitcoinNetwork ?? TEST_NETWORK,
|
|
@@ -275,7 +277,7 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
|
|
|
275
277
|
|
|
276
278
|
try {
|
|
277
279
|
const {signDataPromise, resp} = await tryWithRetries(async(retryCount) => {
|
|
278
|
-
const {signDataPrefetch, response} =
|
|
280
|
+
const {signDataPrefetch, response} = this._lpApi.initToBTC(this.chainIdentifier, lp.url, {
|
|
279
281
|
btcAddress: recipient,
|
|
280
282
|
amount: amountData.amount,
|
|
281
283
|
confirmationTarget: _options.confirmationTarget,
|
|
@@ -284,7 +286,7 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
|
|
|
284
286
|
token: amountData.token,
|
|
285
287
|
offerer: signer,
|
|
286
288
|
exactIn: amountData.exactIn,
|
|
287
|
-
feeRate: throwIfUndefined(feeRatePromise[version]),
|
|
289
|
+
feeRate: throwIfUndefined(feeRatePromise[version], "Network fee rate pre-fetch failed!"),
|
|
288
290
|
additionalParams
|
|
289
291
|
}, this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined);
|
|
290
292
|
|