@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
@@ -9,7 +9,6 @@ const BitcoinUtils_1 = require("../../utils/BitcoinUtils");
9
9
  const btc_signer_1 = require("@scure/btc-signer");
10
10
  const buffer_1 = require("buffer");
11
11
  const IBitcoinWallet_1 = require("../../bitcoin/wallet/IBitcoinWallet");
12
- const IntermediaryAPI_1 = require("../../intermediaries/apis/IntermediaryAPI");
13
12
  const FeeType_1 = require("../../enums/FeeType");
14
13
  const PercentagePPM_1 = require("../../types/fees/PercentagePPM");
15
14
  const TokenAmount_1 = require("../../types/TokenAmount");
@@ -334,7 +333,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
334
333
  * @inheritDoc
335
334
  */
336
335
  isFinished() {
337
- return this._state === SpvFromBTCSwapState.CLAIMED || this._state === SpvFromBTCSwapState.QUOTE_EXPIRED || this._state === SpvFromBTCSwapState.FAILED;
336
+ return this.isSuccessful() || this.isFailed() || this.isQuoteExpired();
338
337
  }
339
338
  /**
340
339
  * @inheritDoc
@@ -588,7 +587,8 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
588
587
  /**
589
588
  * Returns the raw PSBT (not funded), the wallet should fund the PSBT (add its inputs) and importantly **set the nSequence field of the
590
589
  * 2nd input** (input 1 - indexing from 0) to the value returned in `in1sequence`, sign the PSBT and then pass
591
- * it back to the swap with {@link submitPsbt} function.
590
+ * it back to the swap with {@link submitPsbt} function. The transaction should use at least the returned `feeRate`
591
+ * sats/vB as the transaction fee.
592
592
  */
593
593
  async getPsbt() {
594
594
  const res = await this.getTransactionDetails();
@@ -623,7 +623,8 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
623
623
  psbt,
624
624
  psbtHex: serializedPsbt.toString("hex"),
625
625
  psbtBase64: serializedPsbt.toString("base64"),
626
- in1sequence: res.in1sequence
626
+ in1sequence: res.in1sequence,
627
+ feeRate: this.minimumBtcFeeRate
627
628
  };
628
629
  }
629
630
  /**
@@ -637,8 +638,12 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
637
638
  * @param _bitcoinWallet Sender's bitcoin wallet
638
639
  * @param feeRate Optional fee rate in sats/vB for the transaction
639
640
  * @param additionalOutputs additional outputs to add to the PSBT - can be used to collect fees from users
641
+ * @param utxos Pre-fetched list of UTXOs to spend from
642
+ * @param spendFully Instructs the wallet to spend all the passed UTXOs in the transaction without creating any
643
+ * change output, if the `feeRate` is passed, it will also enforce that the feeRate in sats/vB for the resulting
644
+ * transaction is not more than 50% and 10 sats/vB larger (considering also the CPFP adjustments)
640
645
  */
641
- async getFundedPsbt(_bitcoinWallet, feeRate, additionalOutputs) {
646
+ async getFundedPsbt(_bitcoinWallet, feeRate, additionalOutputs, utxos, spendFully) {
642
647
  const bitcoinWallet = (0, BitcoinWalletUtils_1.toBitcoinWallet)(_bitcoinWallet, this.wrapper._btcRpc, this.wrapper._options.bitcoinNetwork);
643
648
  if (feeRate != null) {
644
649
  if (feeRate < this.minimumBtcFeeRate)
@@ -655,7 +660,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
655
660
  script: output.outputScript ?? (0, BitcoinUtils_1.toOutputScript)(this.wrapper._options.bitcoinNetwork, output.address)
656
661
  });
657
662
  });
658
- psbt = await bitcoinWallet.fundPsbt(psbt, feeRate);
663
+ psbt = await bitcoinWallet.fundPsbt(psbt, feeRate, utxos, spendFully);
659
664
  psbt.updateInput(1, { sequence: in1sequence });
660
665
  //Sign every input except the first one
661
666
  const signInputs = [];
@@ -667,7 +672,8 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
667
672
  psbt,
668
673
  psbtHex: serializedPsbt.toString("hex"),
669
674
  psbtBase64: serializedPsbt.toString("base64"),
670
- signInputs
675
+ signInputs,
676
+ feeRate
671
677
  };
672
678
  }
673
679
  /**
@@ -734,7 +740,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
734
740
  this.posted = true;
735
741
  await this._saveAndEmit(SpvFromBTCSwapState.SIGNED);
736
742
  try {
737
- await IntermediaryAPI_1.IntermediaryAPI.initSpvFromBTC(this.chainIdentifier, this.url, {
743
+ await this.wrapper._lpApi.initSpvFromBTC(this.chainIdentifier, this.url, {
738
744
  quoteId: this.quoteId,
739
745
  psbtHex: buffer_1.Buffer.from(psbt.toPSBT(0)).toString("hex")
740
746
  });
@@ -759,8 +765,8 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
759
765
  /**
760
766
  * @inheritDoc
761
767
  */
762
- async sendBitcoinTransaction(wallet, feeRate) {
763
- const { psbt, psbtBase64, psbtHex, signInputs } = await this.getFundedPsbt(wallet, feeRate);
768
+ async sendBitcoinTransaction(wallet, feeRate, utxos, spendFully) {
769
+ const { psbt, psbtBase64, psbtHex, signInputs } = await this.getFundedPsbt(wallet, feeRate, undefined, utxos, spendFully);
764
770
  let signedPsbt;
765
771
  if ((0, IBitcoinWallet_1.isIBitcoinWallet)(wallet)) {
766
772
  signedPsbt = await wallet.signPsbt(psbt, signInputs);
@@ -795,7 +801,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
795
801
  if (this._state === SpvFromBTCSwapState.CLAIMED || this._state === SpvFromBTCSwapState.FRONTED)
796
802
  throw new Error("Swap already settled or fronted!");
797
803
  if (this._state === SpvFromBTCSwapState.CREATED) {
798
- const txId = await this.sendBitcoinTransaction(wallet, options?.feeRate);
804
+ const txId = await this.sendBitcoinTransaction(wallet, options?.feeRate, options?.utxos, options?.spendFully);
799
805
  if (callbacks?.onSourceTransactionSent != null)
800
806
  callbacks.onSourceTransactionSent(txId);
801
807
  }
@@ -816,32 +822,267 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
816
822
  throw new Error("Unexpected state reached!");
817
823
  }
818
824
  /**
819
- * @inheritDoc
820
- *
821
- * @param options.bitcoinFeeRate Optional fee rate to use for the created Bitcoin transaction
822
- * @param options.bitcoinWallet Optional bitcoin wallet address specification to return a funded PSBT,
823
- * if not provided a raw PSBT is returned instead which necessitates the implementor to manually add
824
- * inputs to the bitcoin transaction and **set the nSequence field of the 2nd input** (input 1 -
825
- * indexing from 0) to the value returned in `in1sequence`
825
+ * @internal
826
826
  */
827
- async txsExecute(options) {
828
- if (this._state === SpvFromBTCSwapState.CREATED) {
829
- if (!await this._verifyQuoteValid())
830
- throw new Error("Quote already expired or close to expiry!");
831
- return [
827
+ async _getExecutionStatus(options) {
828
+ const state = this._state;
829
+ const now = Date.now();
830
+ let confirmations;
831
+ let bitcoinPaymentStatus = "inactive";
832
+ let destinationSettlementStatus = "inactive";
833
+ let buildCurrentAction = async () => undefined;
834
+ switch (state) {
835
+ case SpvFromBTCSwapState.QUOTE_EXPIRED:
836
+ case SpvFromBTCSwapState.DECLINED:
837
+ case SpvFromBTCSwapState.FAILED:
838
+ bitcoinPaymentStatus = "expired";
839
+ break;
840
+ case SpvFromBTCSwapState.CREATED: {
841
+ const quoteValid = await this._verifyQuoteValid();
842
+ bitcoinPaymentStatus = quoteValid ? "awaiting" : "soft_expired";
843
+ if (quoteValid) {
844
+ buildCurrentAction = this._buildDepositPsbtAction.bind(this);
845
+ }
846
+ break;
847
+ }
848
+ case SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED:
849
+ case SpvFromBTCSwapState.SIGNED:
850
+ case SpvFromBTCSwapState.POSTED:
851
+ case SpvFromBTCSwapState.BROADCASTED:
852
+ case SpvFromBTCSwapState.FRONTED: {
853
+ const bitcoinPayment = await this.getBitcoinPayment();
854
+ let bitcoinConfirmationDelay = -1;
855
+ let knownBitcoinPaymentStatus;
856
+ if (bitcoinPayment != null) {
857
+ if (bitcoinPayment.confirmations >= bitcoinPayment.targetConfirmations) {
858
+ knownBitcoinPaymentStatus = "confirmed";
859
+ }
860
+ else {
861
+ const result = await this.wrapper._btcRpc.getConfirmationDelay(bitcoinPayment.btcTx, bitcoinPayment.targetConfirmations);
862
+ confirmations = {
863
+ current: bitcoinPayment.confirmations,
864
+ target: bitcoinPayment.targetConfirmations,
865
+ etaSeconds: result ?? -1
866
+ };
867
+ knownBitcoinPaymentStatus = "received";
868
+ bitcoinConfirmationDelay = result ?? -1;
869
+ }
870
+ }
871
+ if (state === SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED)
872
+ bitcoinPaymentStatus = knownBitcoinPaymentStatus ?? "soft_expired";
873
+ if (state === SpvFromBTCSwapState.POSTED || state === SpvFromBTCSwapState.SIGNED)
874
+ bitcoinPaymentStatus = knownBitcoinPaymentStatus ?? "awaiting";
875
+ if (state === SpvFromBTCSwapState.BROADCASTED)
876
+ bitcoinPaymentStatus = knownBitcoinPaymentStatus ?? "received";
877
+ destinationSettlementStatus = "inactive";
878
+ if (state === SpvFromBTCSwapState.FRONTED) {
879
+ bitcoinPaymentStatus = knownBitcoinPaymentStatus ?? "received";
880
+ destinationSettlementStatus = "settled";
881
+ }
882
+ if (state === SpvFromBTCSwapState.SIGNED ||
883
+ state === SpvFromBTCSwapState.POSTED ||
884
+ state === SpvFromBTCSwapState.BROADCASTED) {
885
+ buildCurrentAction = this._buildWaitBitcoinConfirmationsAction.bind(this, bitcoinConfirmationDelay);
886
+ }
887
+ break;
888
+ }
889
+ case SpvFromBTCSwapState.BTC_TX_CONFIRMED:
890
+ bitcoinPaymentStatus = "confirmed";
891
+ if (this.btcTxConfirmedAt == null ||
892
+ options?.maxWaitTillAutomaticSettlementSeconds === 0 ||
893
+ (now - this.btcTxConfirmedAt) > (options?.maxWaitTillAutomaticSettlementSeconds ?? 60) * 1000) {
894
+ destinationSettlementStatus = "awaiting_manual";
895
+ buildCurrentAction = this._buildClaimSmartChainTxAction.bind(this);
896
+ }
897
+ else {
898
+ destinationSettlementStatus = "awaiting_automatic";
899
+ buildCurrentAction = this._buildWaitSettlementAction.bind(this, options?.maxWaitTillAutomaticSettlementSeconds);
900
+ }
901
+ break;
902
+ case SpvFromBTCSwapState.CLAIMED:
903
+ bitcoinPaymentStatus = "confirmed";
904
+ destinationSettlementStatus = "settled";
905
+ break;
906
+ case SpvFromBTCSwapState.CLOSED:
907
+ bitcoinPaymentStatus = "confirmed";
908
+ destinationSettlementStatus = "expired";
909
+ break;
910
+ }
911
+ if (bitcoinPaymentStatus === "confirmed") {
912
+ confirmations = {
913
+ current: this.getRequiredConfirmationsCount(),
914
+ target: this.getRequiredConfirmationsCount(),
915
+ etaSeconds: 0
916
+ };
917
+ }
918
+ return {
919
+ steps: [
832
920
  {
833
- name: "Payment",
834
- description: "Send funds to the bitcoin swap address",
921
+ type: "Payment",
922
+ side: "source",
835
923
  chain: "BITCOIN",
836
- txs: [
837
- options?.bitcoinWallet == null
838
- ? { ...await this.getPsbt(), type: "RAW_PSBT" }
839
- : { ...await this.getFundedPsbt(options.bitcoinWallet, options?.bitcoinFeeRate), type: "FUNDED_PSBT" }
840
- ]
924
+ title: "Bitcoin payment",
925
+ description: "Sign and submit the Bitcoin swap PSBT, then wait for the bitcoin transaction to confirm",
926
+ status: bitcoinPaymentStatus,
927
+ confirmations,
928
+ initTxId: this._data?.btcTx?.txid,
929
+ settleTxId: bitcoinPaymentStatus === "confirmed" ? this._data?.btcTx?.txid : undefined
930
+ },
931
+ {
932
+ type: "Settlement",
933
+ side: "destination",
934
+ chain: this.chainIdentifier,
935
+ title: "Destination settlement",
936
+ description: `Wait for automatic settlement on the ${this.chainIdentifier} side, or settle manually if it takes too long`,
937
+ status: destinationSettlementStatus,
938
+ initTxId: this._frontTxId ?? this._claimTxId,
939
+ settleTxId: this._frontTxId ?? this._claimTxId
940
+ }
941
+ ],
942
+ buildCurrentAction,
943
+ state
944
+ };
945
+ }
946
+ /**
947
+ * @inheritDoc
948
+ * @internal
949
+ */
950
+ async _submitExecutionTransactions(txs, abortSignal, requiredStates, idempotent) {
951
+ if (txs.length === 0)
952
+ throw new Error("Need to submit at least 1 transaction in the array, submitted empty array of transactions!");
953
+ // Handle idempotent calls
954
+ if (idempotent) {
955
+ let idempotencyTriggered = false;
956
+ const txIds = [];
957
+ for (let tx of txs) {
958
+ let parsedTx;
959
+ if (typeof (tx) === "string") {
960
+ try {
961
+ parsedTx = await this.wrapper._chain.deserializeSignedTx(tx);
962
+ }
963
+ catch (e) { }
964
+ try {
965
+ parsedTx = (0, BitcoinUtils_1.parsePsbtTransaction)(tx);
966
+ }
967
+ catch (e) { }
968
+ }
969
+ else {
970
+ parsedTx = tx;
841
971
  }
842
- ];
972
+ if (parsedTx == null) {
973
+ this.logger.debug("_submitExecutionTransactions(): Failed to parse provided execution transaction: ", tx);
974
+ continue;
975
+ }
976
+ if (parsedTx instanceof btc_signer_1.Transaction) {
977
+ // Bitcoin tx
978
+ const btcTx = await this.wrapper._btcRpc.parseTransaction(buffer_1.Buffer.from(parsedTx.toBytes(true)).toString("hex"));
979
+ if (btcTx.txid === this._data?.getTxId()) {
980
+ if (this._state !== SpvFromBTCSwapState.SIGNED && this._state !== SpvFromBTCSwapState.DECLINED)
981
+ idempotencyTriggered = true;
982
+ }
983
+ txIds.push(btcTx.txid);
984
+ }
985
+ else {
986
+ // SC tx
987
+ if (this.wrapper._chain.getTxId != null) {
988
+ const txId = await this.wrapper._chain.getTxId(parsedTx);
989
+ if (this._claimTxId === txId)
990
+ idempotencyTriggered = true;
991
+ txIds.push(txId);
992
+ }
993
+ }
994
+ }
995
+ if (idempotencyTriggered)
996
+ return txIds;
997
+ }
998
+ if (requiredStates != null && !requiredStates.includes(this._state))
999
+ throw new Error("Swap state has changed before transactions were submitted!");
1000
+ if (this._state === SpvFromBTCSwapState.CREATED || this._state === SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED) {
1001
+ let psbt;
1002
+ if (txs.length !== 1)
1003
+ throw new Error("Need to submit exactly 1 signed PSBT!");
1004
+ if (typeof (txs[0]) !== "string" && !(txs[0] instanceof btc_signer_1.Transaction))
1005
+ throw new Error("Must submit a valid PSBT as hex/base64 string or `@scure/btc-signer` Transaction object!");
1006
+ psbt = txs[0];
1007
+ return [await this.submitPsbt(psbt)];
1008
+ }
1009
+ if (this._state === SpvFromBTCSwapState.BTC_TX_CONFIRMED) {
1010
+ const parsedTxs = [];
1011
+ for (let tx of txs) {
1012
+ parsedTxs.push(typeof (tx) === "string" ? await this.wrapper._chain.deserializeSignedTx(tx) : tx);
1013
+ }
1014
+ const txIds = await this.wrapper._chain.sendSignedAndConfirm(parsedTxs, true, abortSignal, false);
1015
+ await this.waitTillClaimed(undefined, abortSignal);
1016
+ return txIds;
843
1017
  }
844
- throw new Error("Invalid swap state to obtain execution txns, required CREATED");
1018
+ throw new Error("Invalid swap state for transaction submission!");
1019
+ }
1020
+ /**
1021
+ * @internal
1022
+ */
1023
+ async _buildDepositPsbtAction(actionOptions) {
1024
+ return {
1025
+ type: "SignPSBT",
1026
+ name: "Deposit on Bitcoin",
1027
+ description: "Send funds to the bitcoin swap address",
1028
+ chain: "BITCOIN",
1029
+ txs: [
1030
+ actionOptions?.bitcoinWallet == null
1031
+ ? { ...await this.getPsbt(), type: "RAW_PSBT" }
1032
+ : { ...await this.getFundedPsbt(actionOptions.bitcoinWallet, actionOptions?.bitcoinFeeRate), type: "FUNDED_PSBT" }
1033
+ ],
1034
+ submitPsbt: async (signedPsbt, idempotent) => {
1035
+ return this._submitExecutionTransactions(Array.isArray(signedPsbt) ? signedPsbt : [signedPsbt], undefined, [SpvFromBTCSwapState.CREATED, SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED], idempotent);
1036
+ }
1037
+ };
1038
+ }
1039
+ /**
1040
+ * @internal
1041
+ */
1042
+ async _buildWaitBitcoinConfirmationsAction(confirmationDelay) {
1043
+ return {
1044
+ type: "Wait",
1045
+ name: "Bitcoin confirmations",
1046
+ description: "Wait for bitcoin transaction to confirm",
1047
+ pollTimeSeconds: 10,
1048
+ expectedTimeSeconds: confirmationDelay === -1 ? -1 : Math.floor(confirmationDelay / 1000),
1049
+ wait: async (maxWaitTimeSeconds, pollIntervalSeconds, abortSignal, btcConfirmationsCallback) => {
1050
+ const abortController = (0, Utils_1.extendAbortController)(abortSignal, maxWaitTimeSeconds, "Timed out waiting for bitcoin transaction");
1051
+ await this.waitForBitcoinTransaction(btcConfirmationsCallback, pollIntervalSeconds, abortController.signal);
1052
+ }
1053
+ };
1054
+ }
1055
+ /**
1056
+ * @internal
1057
+ */
1058
+ async _buildWaitSettlementAction(maxWaitTillAutomaticSettlementSeconds) {
1059
+ return {
1060
+ type: "Wait",
1061
+ name: "Automatic settlement",
1062
+ description: "Wait for bitcoin transaction to confirm",
1063
+ pollTimeSeconds: 5,
1064
+ expectedTimeSeconds: 10,
1065
+ wait: async (maxWaitTimeSeconds, pollIntervalSeconds, abortSignal) => {
1066
+ await this.waitTillClaimedOrFronted(maxWaitTimeSeconds ?? maxWaitTillAutomaticSettlementSeconds ?? 60, abortSignal, pollIntervalSeconds);
1067
+ }
1068
+ };
1069
+ }
1070
+ /**
1071
+ * @internal
1072
+ */
1073
+ async _buildClaimSmartChainTxAction(actionOptions) {
1074
+ const signerAddress = await this.wrapper._getSignerAddress(actionOptions?.manualSettlementSmartChainSigner);
1075
+ return {
1076
+ type: "SignSmartChainTransaction",
1077
+ name: "Settle manually",
1078
+ description: "Manually settle the swap on the destination smart chain",
1079
+ chain: this.chainIdentifier,
1080
+ txs: await this.prepareTransactions(this.txsClaim(actionOptions?.manualSettlementSmartChainSigner)),
1081
+ submitTransactions: async (txs, abortSignal, idempotent) => {
1082
+ return this._submitExecutionTransactions(txs, abortSignal, [SpvFromBTCSwapState.BTC_TX_CONFIRMED], idempotent);
1083
+ },
1084
+ requiredSigner: signerAddress ?? this._getInitiator()
1085
+ };
845
1086
  }
846
1087
  /**
847
1088
  * @inheritDoc
@@ -855,26 +1096,26 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
855
1096
  * @param options.maxWaitTillAutomaticSettlementSeconds Maximum time to wait for an automatic settlement after
856
1097
  * the bitcoin transaction is confirmed (defaults to 60 seconds)
857
1098
  */
858
- async getCurrentActions(options) {
859
- if (this._state === SpvFromBTCSwapState.CREATED) {
860
- try {
861
- return await this.txsExecute(options);
862
- }
863
- catch (e) { }
864
- }
865
- if (this._state === SpvFromBTCSwapState.BTC_TX_CONFIRMED) {
866
- if (this.btcTxConfirmedAt == null ||
867
- options?.maxWaitTillAutomaticSettlementSeconds === 0 ||
868
- (Date.now() - this.btcTxConfirmedAt) > (options?.maxWaitTillAutomaticSettlementSeconds ?? 60) * 1000) {
869
- return [{
870
- name: "Claim",
871
- description: "Manually settle (claim) the swap on the destination smart chain",
872
- chain: this.chainIdentifier,
873
- txs: await this.txsClaim(options?.manualSettlementSmartChainSigner)
874
- }];
875
- }
876
- }
877
- return [];
1099
+ async getExecutionAction(options) {
1100
+ const executionStatus = await this._getExecutionStatus(options);
1101
+ return executionStatus.buildCurrentAction(options);
1102
+ }
1103
+ /**
1104
+ * @inheritDoc
1105
+ */
1106
+ async getExecutionStatus(options) {
1107
+ const executionStatus = await this._getExecutionStatus(options);
1108
+ return {
1109
+ steps: executionStatus.steps,
1110
+ currentAction: options?.skipBuildingAction ? undefined : await executionStatus.buildCurrentAction(options),
1111
+ stateInfo: this._getStateInfo(executionStatus.state)
1112
+ };
1113
+ }
1114
+ /**
1115
+ * @inheritDoc
1116
+ */
1117
+ async getExecutionSteps(options) {
1118
+ return (await this._getExecutionStatus(options)).steps;
878
1119
  }
879
1120
  //////////////////////////////
880
1121
  //// Bitcoin tx listener
@@ -892,6 +1133,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
892
1133
  txId: result.txid,
893
1134
  confirmations: result.confirmations ?? 0,
894
1135
  targetConfirmations: this.vaultRequiredConfirmations,
1136
+ btcTx: result,
895
1137
  inputAddresses: result.inputAddresses
896
1138
  };
897
1139
  }
@@ -1049,11 +1291,11 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
1049
1291
  /**
1050
1292
  * Periodically checks the chain to see whether the swap was finished (claimed or refunded)
1051
1293
  *
1052
- * @param abortSignal
1053
1294
  * @param interval How often to check (in seconds), default to 5s
1295
+ * @param abortSignal
1054
1296
  * @internal
1055
1297
  */
1056
- async watchdogWaitTillResult(abortSignal, interval = 5) {
1298
+ async watchdogWaitTillResult(interval = 5, abortSignal) {
1057
1299
  if (this._data == null)
1058
1300
  throw new Error("Cannot await the result before the btc transaction is sent!");
1059
1301
  let status = { type: base_1.SpvWithdrawalStateType.NOT_FOUND };
@@ -1095,11 +1337,12 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
1095
1337
  * @param maxWaitTimeSeconds Maximum time in seconds to wait for the swap to be settled (by default
1096
1338
  * it waits indefinitely)
1097
1339
  * @param abortSignal Abort signal
1340
+ * @param pollIntervalSeconds How often to poll via the watchdog
1098
1341
  *
1099
1342
  * @returns {boolean} whether the swap was claimed or fronted automatically or not, if the swap was not claimed
1100
1343
  * the user can claim manually through the {@link claim} function
1101
1344
  */
1102
- async waitTillClaimedOrFronted(maxWaitTimeSeconds, abortSignal) {
1345
+ async waitTillClaimedOrFronted(maxWaitTimeSeconds, abortSignal, pollIntervalSeconds) {
1103
1346
  if (this._state === SpvFromBTCSwapState.CLAIMED || this._state === SpvFromBTCSwapState.FRONTED)
1104
1347
  return Promise.resolve(true);
1105
1348
  const abortController = (0, Utils_1.extendAbortController)(abortSignal);
@@ -1114,7 +1357,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
1114
1357
  let res;
1115
1358
  try {
1116
1359
  res = await Promise.race([
1117
- this.watchdogWaitTillResult(abortController.signal),
1360
+ this.watchdogWaitTillResult(pollIntervalSeconds, abortController.signal),
1118
1361
  this.waitTillState(SpvFromBTCSwapState.CLAIMED, "eq", abortController.signal).then(() => 0),
1119
1362
  this.waitTillState(SpvFromBTCSwapState.FRONTED, "eq", abortController.signal).then(() => 1),
1120
1363
  this.waitTillState(SpvFromBTCSwapState.FAILED, "eq", abortController.signal).then(() => 2),
@@ -9,11 +9,13 @@ import { UnifiedSwapEventListener } from "../../events/UnifiedSwapEventListener"
9
9
  import { ISwapPrice } from "../../prices/abstract/ISwapPrice";
10
10
  import { EventEmitter } from "events";
11
11
  import { Intermediary } from "../../intermediaries/Intermediary";
12
+ import { IntermediaryAPI } from "../../intermediaries/apis/IntermediaryAPI";
13
+ import { CoinselectAddressTypes } from "../../bitcoin/coinselect2";
12
14
  import { Transaction } from "@scure/btc-signer";
13
15
  import { ISwap } from "../ISwap";
14
16
  import { IClaimableSwapWrapper } from "../IClaimableSwapWrapper";
15
- import { AmountData } from "../../types/AmountData";
16
17
  import { AllOptional } from "../../utils/TypeUtils";
18
+ import { BitcoinWalletUtxoBase } from "../../bitcoin/wallet/IBitcoinWallet";
17
19
  export type SpvFromBTCOptions = {
18
20
  /**
19
21
  * Optional additional native token to receive as an output of the swap (e.g. STRK on Starknet or cBTC on Citrea).
@@ -53,6 +55,16 @@ export type SpvFromBTCOptions = {
53
55
  * whitelist-only wallets
54
56
  */
55
57
  stickyAddress?: boolean;
58
+ /**
59
+ * A bitcoin wallet UTXOs to fully use as an input for this swap, use this option along with passing `amount` as
60
+ * `undefined` when you want to swap the full BTC balance of the wallet in a single swap
61
+ */
62
+ sourceWalletUtxos?: BitcoinWalletUtxoBase[] | Promise<BitcoinWalletUtxoBase[]>;
63
+ /**
64
+ * Bitcoin fee rate to use when deriving `maxAllowedBitcoinFeeRate` and when calculating the input amount based
65
+ * on the `sourceWalletUtxos`
66
+ */
67
+ bitcoinFeeRate?: Promise<number> | number;
56
68
  /**
57
69
  * @deprecated Use `maxAllowedBitcoinFeeRate` instead!
58
70
  */
@@ -68,6 +80,8 @@ export type SpvFromBTCWrapperOptions = ISwapWrapperOptions & {
68
80
  maxBtcFeeOffset: number;
69
81
  };
70
82
  export type SpvFromBTCTypeDefinition<T extends ChainType> = SwapTypeDefinition<T, SpvFromBTCWrapper<T>, SpvFromBTCSwap<T>>;
83
+ export declare const REQUIRED_SPV_SWAP_VAULT_ADDRESS_TYPE: CoinselectAddressTypes;
84
+ export declare const REQUIRED_SPV_SWAP_LP_ADDRESS_TYPE: CoinselectAddressTypes;
71
85
  /**
72
86
  * New spv vault (UTXO-controlled vault) based swaps for Bitcoin -> Smart chain swaps not requiring
73
87
  * any initiation on the destination chain, and with the added possibility for the user to receive
@@ -125,6 +139,7 @@ export declare class SpvFromBTCWrapper<T extends ChainType> extends ISwapWrapper
125
139
  * @param versionedContracts
126
140
  * @param versionedSynchronizer
127
141
  * @param btcRpc Bitcoin RPC which also supports getting transactions by txoHash
142
+ * @param lpApi
128
143
  * @param options
129
144
  * @param events Instance to use for emitting events
130
145
  */
@@ -138,7 +153,7 @@ export declare class SpvFromBTCWrapper<T extends ChainType> extends ISwapWrapper
138
153
  [version: string]: {
139
154
  synchronizer: RelaySynchronizer<any, T["TX"], any>;
140
155
  };
141
- }, btcRpc: BitcoinRpcWithAddressIndex<any>, options?: AllOptional<SpvFromBTCWrapperOptions>, events?: EventEmitter<{
156
+ }, btcRpc: BitcoinRpcWithAddressIndex<any>, lpApi: IntermediaryAPI, options?: AllOptional<SpvFromBTCWrapperOptions>, events?: EventEmitter<{
142
157
  swapState: [ISwap];
143
158
  }>);
144
159
  private processEventFront;
@@ -162,13 +177,25 @@ export declare class SpvFromBTCWrapper<T extends ChainType> extends ISwapWrapper
162
177
  *
163
178
  * @param amountData
164
179
  * @param options Options as passed to the swap creation function
165
- * @param pricePrefetch
166
- * @param nativeTokenPricePrefetch
167
180
  * @param abortController
168
181
  * @param contractVersion
169
182
  * @private
170
183
  */
171
- private preFetchCallerFeeShare;
184
+ private preFetchCallerFeeInNativeToken;
185
+ /**
186
+ * Pre-fetches caller (watchtower) bounty data for the swap. Doesn't throw, instead returns null and aborts the
187
+ * provided abortController
188
+ *
189
+ * @param amountPrefetch
190
+ * @param totalFeeInNativeTokenPrefetch
191
+ * @param amountData
192
+ * @param options Options as passed to the swap creation function
193
+ * @param pricePrefetch
194
+ * @param nativeTokenPricePrefetch
195
+ * @param abortSignal
196
+ * @private
197
+ */
198
+ private computeCallerFeeShare;
172
199
  /**
173
200
  * Verifies response returned from intermediary
174
201
  *
@@ -177,12 +204,15 @@ export declare class SpvFromBTCWrapper<T extends ChainType> extends ISwapWrapper
177
204
  * @param lp Intermediary
178
205
  * @param options Options as passed to the swap creation function
179
206
  * @param callerFeeShare
180
- * @param bitcoinFeeRatePromise Maximum accepted fee rate from the LPs
207
+ * @param maxBitcoinFeeRatePromise Maximum accepted fee rate from the LPs
208
+ * @param bitcoinFeeRatePromise
181
209
  * @param abortSignal
182
210
  * @private
183
211
  * @throws {IntermediaryError} in case the response is invalid
184
212
  */
185
213
  private verifyReturnedData;
214
+ private amountPrefetch;
215
+ private bitcoinFeeRatePrefetch;
186
216
  /**
187
217
  * Returns a newly created Bitcoin -> Smart chain swap using the SPV vault (UTXO-controlled vault) swap protocol,
188
218
  * with the passed amount. Also allows specifying additional "gas drop" native token that the receipient receives
@@ -195,7 +225,11 @@ export declare class SpvFromBTCWrapper<T extends ChainType> extends ISwapWrapper
195
225
  * @param additionalParams Optional additional parameters sent to the LP when creating the swap
196
226
  * @param abortSignal Abort signal
197
227
  */
198
- create(recipient: string, amountData: AmountData, lps: Intermediary[], options?: SpvFromBTCOptions, additionalParams?: Record<string, any>, abortSignal?: AbortSignal): {
228
+ create(recipient: string, amountData: {
229
+ amount?: bigint;
230
+ token: string;
231
+ exactIn: boolean;
232
+ }, lps: Intermediary[], options?: SpvFromBTCOptions, additionalParams?: Record<string, any>, abortSignal?: AbortSignal): {
199
233
  quote: Promise<SpvFromBTCSwap<T>>;
200
234
  intermediary: Intermediary;
201
235
  }[];