@atomiqlabs/sdk 8.7.7 → 8.9.0

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.
Files changed (152) hide show
  1. package/api/index.d.ts +1 -0
  2. package/api/index.js +3 -0
  3. package/dist/ApiList.d.ts +37 -0
  4. package/dist/ApiList.js +30 -0
  5. package/dist/api/ApiEndpoints.d.ts +393 -0
  6. package/dist/api/ApiEndpoints.js +2 -0
  7. package/dist/api/ApiParser.d.ts +10 -0
  8. package/dist/api/ApiParser.js +134 -0
  9. package/dist/api/ApiTypes.d.ts +157 -0
  10. package/dist/api/ApiTypes.js +75 -0
  11. package/dist/api/SerializedAction.d.ts +40 -0
  12. package/dist/api/SerializedAction.js +59 -0
  13. package/dist/api/SwapperApi.d.ts +50 -0
  14. package/dist/api/SwapperApi.js +431 -0
  15. package/dist/api/index.d.ts +5 -0
  16. package/dist/api/index.js +24 -0
  17. package/dist/bitcoin/coinselect2/accumulative.d.ts +1 -0
  18. package/dist/bitcoin/coinselect2/accumulative.js +1 -1
  19. package/dist/bitcoin/coinselect2/blackjack.d.ts +1 -0
  20. package/dist/bitcoin/coinselect2/blackjack.js +1 -1
  21. package/dist/bitcoin/coinselect2/index.d.ts +3 -2
  22. package/dist/bitcoin/coinselect2/index.js +2 -2
  23. package/dist/bitcoin/coinselect2/utils.d.ts +7 -2
  24. package/dist/bitcoin/coinselect2/utils.js +45 -10
  25. package/dist/bitcoin/wallet/BitcoinWallet.d.ts +8 -25
  26. package/dist/bitcoin/wallet/BitcoinWallet.js +31 -18
  27. package/dist/bitcoin/wallet/IBitcoinWallet.d.ts +40 -2
  28. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.d.ts +7 -2
  29. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.js +10 -4
  30. package/dist/events/UnifiedSwapEventListener.d.ts +4 -3
  31. package/dist/events/UnifiedSwapEventListener.js +8 -2
  32. package/dist/http/HttpUtils.d.ts +4 -2
  33. package/dist/http/HttpUtils.js +10 -4
  34. package/dist/http/paramcoders/client/StreamingFetchPromise.d.ts +2 -1
  35. package/dist/http/paramcoders/client/StreamingFetchPromise.js +3 -2
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.js +1 -0
  38. package/dist/intermediaries/IntermediaryDiscovery.d.ts +7 -2
  39. package/dist/intermediaries/IntermediaryDiscovery.js +4 -4
  40. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +182 -15
  41. package/dist/intermediaries/apis/IntermediaryAPI.js +192 -31
  42. package/dist/intermediaries/auth/SignedKeyBasedAuth.d.ts +14 -0
  43. package/dist/intermediaries/auth/SignedKeyBasedAuth.js +68 -0
  44. package/dist/storage/IUnifiedStorage.d.ts +45 -3
  45. package/dist/storage/UnifiedSwapStorage.d.ts +8 -2
  46. package/dist/storage/UnifiedSwapStorage.js +46 -8
  47. package/dist/swapper/Swapper.d.ts +77 -4
  48. package/dist/swapper/Swapper.js +117 -25
  49. package/dist/swapper/SwapperUtils.d.ts +18 -2
  50. package/dist/swapper/SwapperUtils.js +39 -1
  51. package/dist/swaps/ISwap.d.ts +70 -9
  52. package/dist/swaps/ISwap.js +28 -6
  53. package/dist/swaps/ISwapWrapper.d.ts +11 -1
  54. package/dist/swaps/ISwapWrapper.js +23 -3
  55. package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +1 -1
  56. package/dist/swaps/escrow_swaps/IEscrowSwap.js +4 -2
  57. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.d.ts +2 -1
  58. package/dist/swaps/escrow_swaps/IEscrowSwapWrapper.js +2 -2
  59. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.d.ts +3 -1
  60. package/dist/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.js +3 -2
  61. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +47 -31
  62. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +201 -67
  63. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +3 -1
  64. package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +6 -6
  65. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +82 -15
  66. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +304 -98
  67. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +3 -1
  68. package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +6 -6
  69. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +75 -42
  70. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +424 -87
  71. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.d.ts +3 -1
  72. package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +7 -7
  73. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +54 -11
  74. package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +214 -41
  75. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.d.ts +2 -1
  76. package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +7 -8
  77. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.d.ts +3 -1
  78. package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +5 -5
  79. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +85 -22
  80. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +299 -56
  81. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +41 -7
  82. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +183 -58
  83. package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +53 -12
  84. package/dist/swaps/trusted/ln/LnForGasSwap.js +163 -49
  85. package/dist/swaps/trusted/ln/LnForGasWrapper.js +1 -2
  86. package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +14 -13
  87. package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +30 -47
  88. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.d.ts +3 -1
  89. package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +4 -4
  90. package/dist/types/SwapExecutionAction.d.ts +141 -34
  91. package/dist/types/SwapExecutionAction.js +104 -0
  92. package/dist/types/SwapExecutionStep.d.ts +144 -0
  93. package/dist/types/SwapExecutionStep.js +87 -0
  94. package/dist/types/TokenAmount.d.ts +6 -0
  95. package/dist/types/TokenAmount.js +26 -1
  96. package/dist/utils/BitcoinUtils.d.ts +4 -0
  97. package/dist/utils/BitcoinUtils.js +73 -1
  98. package/dist/utils/BitcoinWalletUtils.d.ts +2 -2
  99. package/dist/utils/Utils.d.ts +3 -1
  100. package/dist/utils/Utils.js +7 -1
  101. package/package.json +7 -4
  102. package/src/api/ApiEndpoints.ts +427 -0
  103. package/src/api/ApiParser.ts +138 -0
  104. package/src/api/ApiTypes.ts +229 -0
  105. package/src/api/SerializedAction.ts +97 -0
  106. package/src/api/SwapperApi.ts +545 -0
  107. package/src/api/index.ts +5 -0
  108. package/src/bitcoin/coinselect2/accumulative.ts +2 -1
  109. package/src/bitcoin/coinselect2/blackjack.ts +2 -1
  110. package/src/bitcoin/coinselect2/index.ts +5 -4
  111. package/src/bitcoin/coinselect2/utils.ts +55 -14
  112. package/src/bitcoin/wallet/BitcoinWallet.ts +69 -57
  113. package/src/bitcoin/wallet/IBitcoinWallet.ts +44 -3
  114. package/src/bitcoin/wallet/SingleAddressBitcoinWallet.ts +12 -4
  115. package/src/events/UnifiedSwapEventListener.ts +11 -3
  116. package/src/http/HttpUtils.ts +10 -4
  117. package/src/http/paramcoders/client/StreamingFetchPromise.ts +4 -2
  118. package/src/index.ts +1 -0
  119. package/src/intermediaries/IntermediaryDiscovery.ts +9 -2
  120. package/src/intermediaries/apis/IntermediaryAPI.ts +335 -35
  121. package/src/intermediaries/auth/SignedKeyBasedAuth.ts +69 -0
  122. package/src/storage/IUnifiedStorage.ts +45 -4
  123. package/src/storage/UnifiedSwapStorage.ts +42 -8
  124. package/src/swapper/Swapper.ts +165 -24
  125. package/src/swapper/SwapperUtils.ts +42 -2
  126. package/src/swaps/ISwap.ts +88 -16
  127. package/src/swaps/ISwapWrapper.ts +28 -3
  128. package/src/swaps/escrow_swaps/IEscrowSwap.ts +5 -3
  129. package/src/swaps/escrow_swaps/IEscrowSwapWrapper.ts +3 -1
  130. package/src/swaps/escrow_swaps/frombtc/IFromBTCLNWrapper.ts +4 -1
  131. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +264 -67
  132. package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +6 -4
  133. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +390 -89
  134. package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +6 -4
  135. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +548 -94
  136. package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +7 -5
  137. package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +276 -45
  138. package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +7 -6
  139. package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +5 -3
  140. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +413 -64
  141. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +239 -61
  142. package/src/swaps/trusted/ln/LnForGasSwap.ts +211 -47
  143. package/src/swaps/trusted/ln/LnForGasWrapper.ts +1 -2
  144. package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +32 -51
  145. package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +5 -3
  146. package/src/types/SwapExecutionAction.ts +266 -43
  147. package/src/types/SwapExecutionStep.ts +224 -0
  148. package/src/types/TokenAmount.ts +36 -2
  149. package/src/utils/BitcoinUtils.ts +73 -0
  150. package/src/utils/BitcoinWalletUtils.ts +2 -2
  151. package/src/utils/Utils.ts +10 -1
  152. 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} = IntermediaryAPI.initFromBTC(
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 {SwapExecutionAction, SwapExecutionActionCommit} from "../../../types/SwapExecutionAction";
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 txsExecute(options?: {
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
- SwapExecutionActionCommit<T>
547
- ]> {
548
- if(this._state!==ToBTCSwapState.CREATED) throw new Error("Invalid swap state, needs to be CREATED!");
549
- const txsCommit = await this.txsCommit(options?.skipChecks);
550
- return [
551
- {
552
- name: "Commit" as const,
553
- description: `Initiates the swap by commiting the funds to the escrow on the ${this.chainIdentifier} side`,
554
- chain: this.chainIdentifier,
555
- txs: txsCommit
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 getCurrentActions(options?: {
746
+ async getExecutionAction(options?: {
568
747
  skipChecks?: boolean,
569
748
  refundSmartChainSigner?: string | T["Signer"] | T["NativeSigner"]
570
- }): Promise<SwapExecutionAction<T>[]> {
571
- if(this._state===ToBTCSwapState.CREATED) {
572
- try {
573
- return await this.txsExecute(options);
574
- } catch (e) {}
575
- }
576
- if(this.isRefundable()) {
577
- return [{
578
- name: "Refund" as const,
579
- description: "Refund the swap after it failed to execute",
580
- chain: this.chainIdentifier,
581
- txs: await this.txsRefund(options?.refundSmartChainSigner)
582
- }];
583
- }
584
- return [];
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 | boolean;
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) this.logger.debug("waitTillCommited(): Resolved from state change");
657
- if(result===true) this.logger.debug("waitTillCommited(): Resolved from watchdog - commited");
658
- if(result===false) {
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 IntermediaryAPI.getRefundAuthorization(this.url, this.getLpIdentifier(), this._data.getSequence());
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 IntermediaryAPI.getRefundAuthorization(this.url, this.getLpIdentifier(), this._data.getSequence());
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 IntermediaryAPI.getRefundAuthorization(this.url, this.getLpIdentifier(), this._data.getSequence());
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
- if(this._refundTxId==null && commitStatus.getRefundTxId) this._refundTxId = await commitStatus.getRefundTxId();
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
- return true;
1284
+ changed = true;
1059
1285
  }
1060
- break;
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
- return true;
1295
+ save = true;
1065
1296
  }
1066
- break;
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} = IntermediaryAPI.initToBTCLN(this.chainIdentifier, lp.url, {
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} = IntermediaryAPI.prepareToBTCLNExactIn(this.chainIdentifier, lp.url, {
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) => IntermediaryAPI.initToBTCLNExactIn(lp.url, {
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} = IntermediaryAPI.initToBTC(this.chainIdentifier, lp.url, {
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