@atomiqlabs/sdk 8.7.7 → 8.8.3

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 (38) hide show
  1. package/dist/bitcoin/coinselect2/accumulative.d.ts +1 -0
  2. package/dist/bitcoin/coinselect2/accumulative.js +1 -1
  3. package/dist/bitcoin/coinselect2/blackjack.d.ts +1 -0
  4. package/dist/bitcoin/coinselect2/blackjack.js +1 -1
  5. package/dist/bitcoin/coinselect2/index.d.ts +3 -2
  6. package/dist/bitcoin/coinselect2/index.js +2 -2
  7. package/dist/bitcoin/coinselect2/utils.d.ts +7 -2
  8. package/dist/bitcoin/coinselect2/utils.js +45 -10
  9. package/dist/bitcoin/wallet/BitcoinWallet.d.ts +8 -25
  10. package/dist/bitcoin/wallet/BitcoinWallet.js +31 -18
  11. package/dist/bitcoin/wallet/IBitcoinWallet.d.ts +40 -2
  12. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.d.ts +7 -2
  13. package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.js +10 -4
  14. package/dist/intermediaries/apis/IntermediaryAPI.d.ts +11 -1
  15. package/dist/intermediaries/apis/IntermediaryAPI.js +18 -3
  16. package/dist/swapper/Swapper.d.ts +41 -1
  17. package/dist/swapper/Swapper.js +63 -7
  18. package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +9 -3
  19. package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +9 -5
  20. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +38 -6
  21. package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +178 -53
  22. package/dist/utils/BitcoinUtils.d.ts +2 -0
  23. package/dist/utils/BitcoinUtils.js +40 -1
  24. package/dist/utils/BitcoinWalletUtils.d.ts +2 -2
  25. package/package.json +1 -1
  26. package/src/bitcoin/coinselect2/accumulative.ts +2 -1
  27. package/src/bitcoin/coinselect2/blackjack.ts +2 -1
  28. package/src/bitcoin/coinselect2/index.ts +5 -4
  29. package/src/bitcoin/coinselect2/utils.ts +55 -14
  30. package/src/bitcoin/wallet/BitcoinWallet.ts +69 -57
  31. package/src/bitcoin/wallet/IBitcoinWallet.ts +44 -3
  32. package/src/bitcoin/wallet/SingleAddressBitcoinWallet.ts +12 -4
  33. package/src/intermediaries/apis/IntermediaryAPI.ts +21 -5
  34. package/src/swapper/Swapper.ts +79 -7
  35. package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +20 -7
  36. package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +234 -58
  37. package/src/utils/BitcoinUtils.ts +41 -0
  38. package/src/utils/BitcoinWalletUtils.ts +2 -2
@@ -35,6 +35,7 @@ const LNURLPay_1 = require("../types/lnurl/LNURLPay");
35
35
  const RetryUtils_1 = require("../utils/RetryUtils");
36
36
  const IEscrowSwap_1 = require("../swaps/escrow_swaps/IEscrowSwap");
37
37
  const LightningInvoiceCreateService_1 = require("../types/wallets/LightningInvoiceCreateService");
38
+ const BitcoinWalletUtils_1 = require("../utils/BitcoinWalletUtils");
38
39
  /**
39
40
  * Core orchestrator for all atomiq swap operations
40
41
  *
@@ -343,7 +344,7 @@ class Swapper extends events_1.EventEmitter {
343
344
  throw new Error("Invalid chain identifier! Unknown chain: " + chainIdentifier);
344
345
  let candidates;
345
346
  const inBtc = swapType === SwapType_1.SwapType.TO_BTCLN || swapType === SwapType_1.SwapType.TO_BTC ? !amountData.exactIn : amountData.exactIn;
346
- if (!inBtc) {
347
+ if (!inBtc || amountData.amount == null) {
347
348
  //Get candidates not based on the amount
348
349
  candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token);
349
350
  }
@@ -355,7 +356,7 @@ class Swapper extends events_1.EventEmitter {
355
356
  this.logger.warn("createSwap(): No valid intermediary found to execute the swap with, reloading intermediary database...");
356
357
  await this.intermediaryDiscovery.reloadIntermediaries();
357
358
  swapLimitsChanged = true;
358
- if (!inBtc) {
359
+ if (!inBtc || amountData.amount == null) {
359
360
  //Get candidates not based on the amount
360
361
  candidates = this.intermediaryDiscovery.getSwapCandidates(chainIdentifier, swapType, amountData.token);
361
362
  }
@@ -441,10 +442,12 @@ class Swapper extends events_1.EventEmitter {
441
442
  }
442
443
  if (min != null && max != null) {
443
444
  let msg = "Swap amount too high or too low! Try swapping a different amount.";
444
- if (min > amountData.amount)
445
- msg = "Swap amount too low! Try swapping a higher amount.";
446
- if (max < amountData.amount)
447
- msg = "Swap amount too high! Try swapping a lower amount.";
445
+ if (amountData.amount != null) {
446
+ if (min > amountData.amount)
447
+ msg = "Swap amount too low! Try swapping a higher amount.";
448
+ if (max < amountData.amount)
449
+ msg = "Swap amount too high! Try swapping a lower amount.";
450
+ }
448
451
  reject(new RequestError_1.OutOfBoundsError(msg, 400, min, max));
449
452
  return;
450
453
  }
@@ -612,7 +615,7 @@ class Swapper extends events_1.EventEmitter {
612
615
  throw new Error("Invalid " + chainIdentifier + " address");
613
616
  recipient = this._chains[chainIdentifier].chainInterface.normalizeAddress(recipient);
614
617
  const amountData = {
615
- amount,
618
+ amount: amount ?? undefined,
616
619
  token: tokenAddress,
617
620
  exactIn: !exactOut
618
621
  };
@@ -907,6 +910,59 @@ class Swapper extends events_1.EventEmitter {
907
910
  }
908
911
  throw new Error("Unsupported swap type");
909
912
  }
913
+ /**
914
+ * A helper function to sweep all the funds from a given wallet in a single swap, after getting the quote you can
915
+ * execute the swap by passing the returned `feeRate` and `utxos` to the {@link SpvFromBTCSwap.execute},
916
+ * {@link SpvFromBTCSwap.getFundedPsbt} or {@link SpvFromBTCSwap.sendBitcoinTransaction} functions along
917
+ * with `spendFully=true`.
918
+ *
919
+ * @example
920
+ * Create the swap first using this function
921
+ * ```ts
922
+ * const {swap, utxos, btcFeeRate} = await swapper.sweepBitcoinWallet(wallet, Tokens.CITREA.CBTC, dstAddress);
923
+ * ```
924
+ * Then execute it using one of these execution paths - ensure that you supply the returned `utxos`, `btcFeeRate`
925
+ * params and also set `spendFully` to `true`!
926
+ *
927
+ * a) Execute and pass the returned utxos and btcFeeRate:
928
+ * ```ts
929
+ * await swap.execute(wallet, undefined, {feeRate: btcFeeRate, utxos: utxos, spendFully: true});
930
+ * ```
931
+ *
932
+ * b) Get funded PSBT to sign externally:
933
+ * ```ts
934
+ * const {psbt, psbtHex, psbtBase64, signInputs} = await swap.getFundedPsbt(wallet, btcFeeRate, undefined, utxos, true);
935
+ * // Sign the psbt at the specified signInputs indices
936
+ * const signedPsbt = ...;
937
+ * // Then submit back to the SDK
938
+ * await swap.submitPsbt(signedPsbt);
939
+ * ```
940
+ *
941
+ * c) Only sign and send the signed PSBT with the provided wallet:
942
+ * ```ts
943
+ * await swap.sendBitcoinTransaction(wallet, btcFeeRate, utxos, true);
944
+ * ```
945
+ */
946
+ async sweepBitcoinWallet(srcWallet, _dstToken, dstAddress, options) {
947
+ const dstToken = typeof (_dstToken) === "string" ? this.getToken(_dstToken) : _dstToken;
948
+ if (!(0, Token_1.isSCToken)(dstToken))
949
+ throw new Error("Destination token must be a smart chain token!");
950
+ const wallet = (0, BitcoinWalletUtils_1.toBitcoinWallet)(srcWallet, this._bitcoinRpc, this.bitcoinNetwork);
951
+ if (wallet.getUtxoPool == null)
952
+ throw new Error("Wallet needs to support the `getUtxoPool()` function!");
953
+ const walletUtxosPromise = wallet.getUtxoPool();
954
+ const bitcoinFeeRatePromise = options?.bitcoinFeeRate ?? wallet.getFeeRate();
955
+ const swap = await this.createFromBTCSwapNew(dstToken.chainId, dstAddress, dstToken.address, null, false, undefined, {
956
+ ...options,
957
+ sourceWalletUtxos: walletUtxosPromise,
958
+ bitcoinFeeRate: bitcoinFeeRatePromise
959
+ });
960
+ return {
961
+ swap,
962
+ utxos: await walletUtxosPromise,
963
+ btcFeeRate: Math.max(swap.minimumBtcFeeRate, await bitcoinFeeRatePromise)
964
+ };
965
+ }
910
966
  async getAllSwaps(chainId, signer) {
911
967
  const queryParams = [];
912
968
  if (signer != null)
@@ -4,7 +4,7 @@ import { SwapType } from "../../enums/SwapType";
4
4
  import { SpvFromBTCTypeDefinition, SpvFromBTCWrapper } from "./SpvFromBTCWrapper";
5
5
  import { Transaction } from "@scure/btc-signer";
6
6
  import { Fee } from "../../types/fees/Fee";
7
- import { IBitcoinWallet } from "../../bitcoin/wallet/IBitcoinWallet";
7
+ import { BitcoinWalletUtxo, IBitcoinWallet } from "../../bitcoin/wallet/IBitcoinWallet";
8
8
  import { IBTCWalletSwap } from "../IBTCWalletSwap";
9
9
  import { ISwapWithGasDrop } from "../ISwapWithGasDrop";
10
10
  import { MinimalBitcoinWalletInterface, MinimalBitcoinWalletInterfaceWithSigner } from "../../types/wallets/MinimalBitcoinWalletInterface";
@@ -423,6 +423,10 @@ export declare class SpvFromBTCSwap<T extends ChainType> extends ISwap<T, SpvFro
423
423
  * @param _bitcoinWallet Sender's bitcoin wallet
424
424
  * @param feeRate Optional fee rate in sats/vB for the transaction
425
425
  * @param additionalOutputs additional outputs to add to the PSBT - can be used to collect fees from users
426
+ * @param utxos Pre-fetched list of UTXOs to spend from
427
+ * @param spendFully Instructs the wallet to spend all the passed UTXOs in the transaction without creating any
428
+ * change output, if the `feeRate` is passed, it will also enforce that the feeRate in sats/vB for the resulting
429
+ * transaction is not more than 50% and 10 sats/vB larger (considering also the CPFP adjustments)
426
430
  */
427
431
  getFundedPsbt(_bitcoinWallet: IBitcoinWallet | MinimalBitcoinWalletInterface, feeRate?: number, additionalOutputs?: ({
428
432
  amount: bigint;
@@ -430,7 +434,7 @@ export declare class SpvFromBTCSwap<T extends ChainType> extends ISwap<T, SpvFro
430
434
  } | {
431
435
  amount: bigint;
432
436
  address: string;
433
- })[]): Promise<{
437
+ })[], utxos?: BitcoinWalletUtxo[], spendFully?: boolean): Promise<{
434
438
  psbt: Transaction;
435
439
  psbtHex: string;
436
440
  psbtBase64: string;
@@ -447,7 +451,7 @@ export declare class SpvFromBTCSwap<T extends ChainType> extends ISwap<T, SpvFro
447
451
  /**
448
452
  * @inheritDoc
449
453
  */
450
- sendBitcoinTransaction(wallet: IBitcoinWallet | MinimalBitcoinWalletInterfaceWithSigner, feeRate?: number): Promise<string>;
454
+ sendBitcoinTransaction(wallet: IBitcoinWallet | MinimalBitcoinWalletInterfaceWithSigner, feeRate?: number, utxos?: BitcoinWalletUtxo[], spendFully?: boolean): Promise<string>;
451
455
  /**
452
456
  * Executes the swap with the provided bitcoin wallet
453
457
  *
@@ -469,6 +473,8 @@ export declare class SpvFromBTCSwap<T extends ChainType> extends ISwap<T, SpvFro
469
473
  abortSignal?: AbortSignal;
470
474
  btcTxCheckIntervalSeconds?: number;
471
475
  maxWaitTillAutomaticSettlementSeconds?: number;
476
+ utxos?: BitcoinWalletUtxo[];
477
+ spendFully?: boolean;
472
478
  }): Promise<boolean>;
473
479
  /**
474
480
  * @inheritDoc
@@ -637,8 +637,12 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
637
637
  * @param _bitcoinWallet Sender's bitcoin wallet
638
638
  * @param feeRate Optional fee rate in sats/vB for the transaction
639
639
  * @param additionalOutputs additional outputs to add to the PSBT - can be used to collect fees from users
640
+ * @param utxos Pre-fetched list of UTXOs to spend from
641
+ * @param spendFully Instructs the wallet to spend all the passed UTXOs in the transaction without creating any
642
+ * change output, if the `feeRate` is passed, it will also enforce that the feeRate in sats/vB for the resulting
643
+ * transaction is not more than 50% and 10 sats/vB larger (considering also the CPFP adjustments)
640
644
  */
641
- async getFundedPsbt(_bitcoinWallet, feeRate, additionalOutputs) {
645
+ async getFundedPsbt(_bitcoinWallet, feeRate, additionalOutputs, utxos, spendFully) {
642
646
  const bitcoinWallet = (0, BitcoinWalletUtils_1.toBitcoinWallet)(_bitcoinWallet, this.wrapper._btcRpc, this.wrapper._options.bitcoinNetwork);
643
647
  if (feeRate != null) {
644
648
  if (feeRate < this.minimumBtcFeeRate)
@@ -655,7 +659,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
655
659
  script: output.outputScript ?? (0, BitcoinUtils_1.toOutputScript)(this.wrapper._options.bitcoinNetwork, output.address)
656
660
  });
657
661
  });
658
- psbt = await bitcoinWallet.fundPsbt(psbt, feeRate);
662
+ psbt = await bitcoinWallet.fundPsbt(psbt, feeRate, utxos, spendFully);
659
663
  psbt.updateInput(1, { sequence: in1sequence });
660
664
  //Sign every input except the first one
661
665
  const signInputs = [];
@@ -759,8 +763,8 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
759
763
  /**
760
764
  * @inheritDoc
761
765
  */
762
- async sendBitcoinTransaction(wallet, feeRate) {
763
- const { psbt, psbtBase64, psbtHex, signInputs } = await this.getFundedPsbt(wallet, feeRate);
766
+ async sendBitcoinTransaction(wallet, feeRate, utxos, spendFully) {
767
+ const { psbt, psbtBase64, psbtHex, signInputs } = await this.getFundedPsbt(wallet, feeRate, undefined, utxos, spendFully);
764
768
  let signedPsbt;
765
769
  if ((0, IBitcoinWallet_1.isIBitcoinWallet)(wallet)) {
766
770
  signedPsbt = await wallet.signPsbt(psbt, signInputs);
@@ -795,7 +799,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
795
799
  if (this._state === SpvFromBTCSwapState.CLAIMED || this._state === SpvFromBTCSwapState.FRONTED)
796
800
  throw new Error("Swap already settled or fronted!");
797
801
  if (this._state === SpvFromBTCSwapState.CREATED) {
798
- const txId = await this.sendBitcoinTransaction(wallet, options?.feeRate);
802
+ const txId = await this.sendBitcoinTransaction(wallet, options?.feeRate, options?.utxos, options?.spendFully);
799
803
  if (callbacks?.onSourceTransactionSent != null)
800
804
  callbacks.onSourceTransactionSent(txId);
801
805
  }
@@ -9,11 +9,12 @@ 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 { CoinselectAddressTypes } from "../../bitcoin/coinselect2";
12
13
  import { Transaction } from "@scure/btc-signer";
13
14
  import { ISwap } from "../ISwap";
14
15
  import { IClaimableSwapWrapper } from "../IClaimableSwapWrapper";
15
- import { AmountData } from "../../types/AmountData";
16
16
  import { AllOptional } from "../../utils/TypeUtils";
17
+ import { BitcoinWalletUtxoBase } from "../../bitcoin/wallet/IBitcoinWallet";
17
18
  export type SpvFromBTCOptions = {
18
19
  /**
19
20
  * Optional additional native token to receive as an output of the swap (e.g. STRK on Starknet or cBTC on Citrea).
@@ -53,6 +54,16 @@ export type SpvFromBTCOptions = {
53
54
  * whitelist-only wallets
54
55
  */
55
56
  stickyAddress?: boolean;
57
+ /**
58
+ * A bitcoin wallet UTXOs to fully use as an input for this swap, use this option along with passing `amount` as
59
+ * `undefined` when you want to swap the full BTC balance of the wallet in a single swap
60
+ */
61
+ sourceWalletUtxos?: BitcoinWalletUtxoBase[] | Promise<BitcoinWalletUtxoBase[]>;
62
+ /**
63
+ * Bitcoin fee rate to use when deriving `maxAllowedBitcoinFeeRate` and when calculating the input amount based
64
+ * on the `sourceWalletUtxos`
65
+ */
66
+ bitcoinFeeRate?: Promise<number> | number;
56
67
  /**
57
68
  * @deprecated Use `maxAllowedBitcoinFeeRate` instead!
58
69
  */
@@ -68,6 +79,8 @@ export type SpvFromBTCWrapperOptions = ISwapWrapperOptions & {
68
79
  maxBtcFeeOffset: number;
69
80
  };
70
81
  export type SpvFromBTCTypeDefinition<T extends ChainType> = SwapTypeDefinition<T, SpvFromBTCWrapper<T>, SpvFromBTCSwap<T>>;
82
+ export declare const REQUIRED_SPV_SWAP_VAULT_ADDRESS_TYPE: CoinselectAddressTypes;
83
+ export declare const REQUIRED_SPV_SWAP_LP_ADDRESS_TYPE: CoinselectAddressTypes;
71
84
  /**
72
85
  * New spv vault (UTXO-controlled vault) based swaps for Bitcoin -> Smart chain swaps not requiring
73
86
  * any initiation on the destination chain, and with the added possibility for the user to receive
@@ -162,13 +175,25 @@ export declare class SpvFromBTCWrapper<T extends ChainType> extends ISwapWrapper
162
175
  *
163
176
  * @param amountData
164
177
  * @param options Options as passed to the swap creation function
165
- * @param pricePrefetch
166
- * @param nativeTokenPricePrefetch
167
178
  * @param abortController
168
179
  * @param contractVersion
169
180
  * @private
170
181
  */
171
- private preFetchCallerFeeShare;
182
+ private preFetchCallerFeeInNativeToken;
183
+ /**
184
+ * Pre-fetches caller (watchtower) bounty data for the swap. Doesn't throw, instead returns null and aborts the
185
+ * provided abortController
186
+ *
187
+ * @param amountPrefetch
188
+ * @param totalFeeInNativeTokenPrefetch
189
+ * @param amountData
190
+ * @param options Options as passed to the swap creation function
191
+ * @param pricePrefetch
192
+ * @param nativeTokenPricePrefetch
193
+ * @param abortSignal
194
+ * @private
195
+ */
196
+ private computeCallerFeeShare;
172
197
  /**
173
198
  * Verifies response returned from intermediary
174
199
  *
@@ -177,12 +202,15 @@ export declare class SpvFromBTCWrapper<T extends ChainType> extends ISwapWrapper
177
202
  * @param lp Intermediary
178
203
  * @param options Options as passed to the swap creation function
179
204
  * @param callerFeeShare
180
- * @param bitcoinFeeRatePromise Maximum accepted fee rate from the LPs
205
+ * @param maxBitcoinFeeRatePromise Maximum accepted fee rate from the LPs
206
+ * @param bitcoinFeeRatePromise
181
207
  * @param abortSignal
182
208
  * @private
183
209
  * @throws {IntermediaryError} in case the response is invalid
184
210
  */
185
211
  private verifyReturnedData;
212
+ private amountPrefetch;
213
+ private bitcoinFeeRatePrefetch;
186
214
  /**
187
215
  * Returns a newly created Bitcoin -> Smart chain swap using the SPV vault (UTXO-controlled vault) swap protocol,
188
216
  * with the passed amount. Also allows specifying additional "gas drop" native token that the receipient receives
@@ -195,7 +223,11 @@ export declare class SpvFromBTCWrapper<T extends ChainType> extends ISwapWrapper
195
223
  * @param additionalParams Optional additional parameters sent to the LP when creating the swap
196
224
  * @param abortSignal Abort signal
197
225
  */
198
- create(recipient: string, amountData: AmountData, lps: Intermediary[], options?: SpvFromBTCOptions, additionalParams?: Record<string, any>, abortSignal?: AbortSignal): {
226
+ create(recipient: string, amountData: {
227
+ amount?: bigint;
228
+ token: string;
229
+ exactIn: boolean;
230
+ }, lps: Intermediary[], options?: SpvFromBTCOptions, additionalParams?: Record<string, any>, abortSignal?: AbortSignal): {
199
231
  quote: Promise<SpvFromBTCSwap<T>>;
200
232
  intermediary: Intermediary;
201
233
  }[];