@xchainjs/xchain-bitcoin 2.1.0 → 2.2.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.
package/lib/client.d.ts CHANGED
@@ -47,11 +47,12 @@ declare abstract class Client extends UTXOClient {
47
47
  * @param params Transaction parameters
48
48
  * @returns Enhanced transaction build result with PSBT, UTXOs, and inputs
49
49
  */
50
- buildTxEnhanced({ amount, recipient, memo, feeRate, sender, spendPendingUTXO, utxoSelectionPreferences, }: TxParams & {
50
+ buildTxEnhanced({ amount, recipient, memo, feeRate, sender, spendPendingUTXO, utxoSelectionPreferences, selectedUtxos, }: TxParams & {
51
51
  feeRate: FeeRate;
52
52
  sender: Address;
53
53
  spendPendingUTXO?: boolean;
54
54
  utxoSelectionPreferences?: UtxoSelectionPreferences;
55
+ selectedUtxos?: UTXO[];
55
56
  }): Promise<{
56
57
  psbt: Bitcoin.Psbt;
57
58
  utxos: UTXO[];
@@ -77,13 +78,14 @@ declare abstract class Client extends UTXOClient {
77
78
  * @param params Send max parameters
78
79
  * @returns Transaction details with maximum sendable amount
79
80
  */
80
- sendMax({ sender, recipient, memo, feeRate, spendPendingUTXO, utxoSelectionPreferences, }: {
81
+ sendMax({ sender, recipient, memo, feeRate, spendPendingUTXO, utxoSelectionPreferences, selectedUtxos, }: {
81
82
  sender: Address;
82
83
  recipient: Address;
83
84
  memo?: string;
84
85
  feeRate: FeeRate;
85
86
  spendPendingUTXO?: boolean;
86
87
  utxoSelectionPreferences?: UtxoSelectionPreferences;
88
+ selectedUtxos?: UTXO[];
87
89
  }): Promise<{
88
90
  psbt: Bitcoin.Psbt;
89
91
  utxos: UTXO[];
@@ -96,13 +98,14 @@ declare abstract class Client extends UTXOClient {
96
98
  * @param params Send max parameters
97
99
  * @returns Prepared transaction with maximum sendable amount
98
100
  */
99
- prepareMaxTx({ sender, recipient, memo, feeRate, spendPendingUTXO, utxoSelectionPreferences, }: {
101
+ prepareMaxTx({ sender, recipient, memo, feeRate, spendPendingUTXO, utxoSelectionPreferences, selectedUtxos, }: {
100
102
  sender: Address;
101
103
  recipient: Address;
102
104
  memo?: string;
103
105
  feeRate: FeeRate;
104
106
  spendPendingUTXO?: boolean;
105
107
  utxoSelectionPreferences?: UtxoSelectionPreferences;
108
+ selectedUtxos?: UTXO[];
106
109
  }): Promise<PreparedTx & {
107
110
  maxAmount: number;
108
111
  fee: number;
@@ -113,11 +116,12 @@ declare abstract class Client extends UTXOClient {
113
116
  * @param params The transfer options with enhanced UTXO selection preferences.
114
117
  * @returns The raw unsigned transaction with enhanced error handling.
115
118
  */
116
- prepareTxEnhanced({ sender, memo, amount, recipient, spendPendingUTXO, feeRate, utxoSelectionPreferences, }: TxParams & {
119
+ prepareTxEnhanced({ sender, memo, amount, recipient, spendPendingUTXO, feeRate, utxoSelectionPreferences, selectedUtxos, }: TxParams & {
117
120
  sender: Address;
118
121
  feeRate: FeeRate;
119
122
  spendPendingUTXO?: boolean;
120
123
  utxoSelectionPreferences?: UtxoSelectionPreferences;
124
+ selectedUtxos?: UTXO[];
121
125
  }): Promise<PreparedTx>;
122
126
  /**
123
127
  * Prepare transfer with enhanced validation and performance.
@@ -1,6 +1,6 @@
1
1
  import { FeeRate, TxHash } from '@xchainjs/xchain-client';
2
2
  import { Address } from '@xchainjs/xchain-util';
3
- import { TxParams, UtxoClientParams, UtxoSelectionPreferences } from '@xchainjs/xchain-utxo';
3
+ import { TxParams, UTXO, UtxoClientParams, UtxoSelectionPreferences } from '@xchainjs/xchain-utxo';
4
4
  import { Client } from './client';
5
5
  import { AddressFormat } from './types';
6
6
  /**
@@ -47,6 +47,7 @@ declare class ClientKeystore extends Client {
47
47
  transfer(params: TxParams & {
48
48
  feeRate?: FeeRate;
49
49
  utxoSelectionPreferences?: UtxoSelectionPreferences;
50
+ selectedUtxos?: UTXO[];
50
51
  }): Promise<TxHash>;
51
52
  /**
52
53
  * Transfer the maximum amount of Bitcoin (sweep).
@@ -66,6 +67,7 @@ declare class ClientKeystore extends Client {
66
67
  feeRate?: FeeRate;
67
68
  walletIndex?: number;
68
69
  utxoSelectionPreferences?: UtxoSelectionPreferences;
70
+ selectedUtxos?: UTXO[];
69
71
  }): Promise<{
70
72
  hash: TxHash;
71
73
  maxAmount: number;
@@ -1,7 +1,7 @@
1
1
  import AppBtc from '@ledgerhq/hw-app-btc';
2
2
  import { FeeRate, TxHash } from '@xchainjs/xchain-client';
3
3
  import { Address } from '@xchainjs/xchain-util';
4
- import { TxParams, UtxoClientParams, UtxoSelectionPreferences } from '@xchainjs/xchain-utxo';
4
+ import { TxParams, UTXO, UtxoClientParams, UtxoSelectionPreferences } from '@xchainjs/xchain-utxo';
5
5
  import { Client } from './client';
6
6
  import { AddressFormat } from './types';
7
7
  /**
@@ -21,5 +21,17 @@ declare class ClientLedger extends Client {
21
21
  feeRate?: FeeRate;
22
22
  utxoSelectionPreferences?: UtxoSelectionPreferences;
23
23
  }): Promise<TxHash>;
24
+ transferMax(params: {
25
+ recipient: Address;
26
+ memo?: string;
27
+ feeRate?: FeeRate;
28
+ walletIndex?: number;
29
+ utxoSelectionPreferences?: UtxoSelectionPreferences;
30
+ selectedUtxos?: UTXO[];
31
+ }): Promise<{
32
+ hash: TxHash;
33
+ maxAmount: number;
34
+ fee: number;
35
+ }>;
24
36
  }
25
37
  export { ClientLedger };
package/lib/index.esm.js CHANGED
@@ -4,7 +4,7 @@ import { getSeed } from '@xchainjs/xchain-crypto';
4
4
  import { HDKey } from '@scure/bip32';
5
5
  import * as Bitcoin from 'bitcoinjs-lib';
6
6
  import { ECPairFactory } from 'ecpair';
7
- import { Client as Client$1, UtxoError } from '@xchainjs/xchain-utxo';
7
+ import { Client as Client$1, UtxoTransactionValidator, UtxoError } from '@xchainjs/xchain-utxo';
8
8
  import { AssetType } from '@xchainjs/xchain-util';
9
9
  import { SochainProvider, SochainNetwork, HaskoinProvider, HaskoinNetwork, BlockcypherProvider, BlockcypherNetwork, BitgoProvider } from '@xchainjs/xchain-utxo-providers';
10
10
  import AppBtc from '@ledgerhq/hw-app-btc';
@@ -289,7 +289,7 @@ class Client extends Client$1 {
289
289
  * @returns Enhanced transaction build result with PSBT, UTXOs, and inputs
290
290
  */
291
291
  buildTxEnhanced(_a) {
292
- return __awaiter(this, arguments, void 0, function* ({ amount, recipient, memo, feeRate, sender, spendPendingUTXO = true, utxoSelectionPreferences, }) {
292
+ return __awaiter(this, arguments, void 0, function* ({ amount, recipient, memo, feeRate, sender, spendPendingUTXO = true, utxoSelectionPreferences, selectedUtxos, }) {
293
293
  try {
294
294
  // Comprehensive input validation
295
295
  this.validateTransactionInputs({
@@ -299,9 +299,16 @@ class Client extends Client$1 {
299
299
  sender,
300
300
  feeRate,
301
301
  });
302
- // Get validated UTXOs
303
- const confirmedOnly = !spendPendingUTXO;
304
- const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
302
+ // Use provided UTXOs (coin control) or fetch from chain
303
+ let utxos;
304
+ if (selectedUtxos && selectedUtxos.length > 0) {
305
+ UtxoTransactionValidator.validateUtxoSet(selectedUtxos);
306
+ utxos = selectedUtxos;
307
+ }
308
+ else {
309
+ const confirmedOnly = !spendPendingUTXO;
310
+ utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
311
+ }
305
312
  const compiledMemo = memo ? this.compileMemo(memo) : null;
306
313
  const targetValue = amount.amount().toNumber();
307
314
  const extraOutputs = 1 + (compiledMemo ? 1 : 0); // recipient + optional memo (change calculated separately)
@@ -382,7 +389,7 @@ class Client extends Client$1 {
382
389
  * @returns Transaction details with maximum sendable amount
383
390
  */
384
391
  sendMax(_a) {
385
- return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
392
+ return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, selectedUtxos, }) {
386
393
  try {
387
394
  // Basic validation (skip amount validation since we're calculating max)
388
395
  if (!(recipient === null || recipient === void 0 ? void 0 : recipient.trim())) {
@@ -395,20 +402,32 @@ class Client extends Client$1 {
395
402
  throw UtxoError.invalidAddress(sender, this.network);
396
403
  }
397
404
  // Memo validation is handled by validateTransactionInputs
398
- // Get validated UTXOs
399
- const confirmedOnly = !spendPendingUTXO;
400
- const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
405
+ // Use provided UTXOs (coin control) or fetch from chain
406
+ let utxos;
407
+ if (selectedUtxos && selectedUtxos.length > 0) {
408
+ UtxoTransactionValidator.validateUtxoSet(selectedUtxos);
409
+ utxos = selectedUtxos;
410
+ }
411
+ else {
412
+ const confirmedOnly = !spendPendingUTXO;
413
+ utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
414
+ }
401
415
  // Calculate maximum sendable amount
402
416
  const maxCalc = this.calculateMaxSendableAmount(utxos, Math.ceil(feeRate), !!memo, utxoSelectionPreferences);
403
417
  const compiledMemo = memo ? this.compileMemo(memo) : null;
404
418
  const psbt = new Bitcoin.Psbt({ network: btcNetwork(this.network) });
405
419
  // Add inputs
406
420
  if (this.addressFormat === AddressFormat.P2WPKH) {
407
- maxCalc.inputs.forEach((utxo) => psbt.addInput({
408
- hash: utxo.hash,
409
- index: utxo.index,
410
- witnessUtxo: utxo.witnessUtxo,
411
- }));
421
+ maxCalc.inputs.forEach((utxo) => {
422
+ if (!utxo.witnessUtxo) {
423
+ throw UtxoError.fromUnknown(new Error(`Missing witnessUtxo for UTXO ${utxo.hash}:${utxo.index}`), 'sendMax');
424
+ }
425
+ psbt.addInput({
426
+ hash: utxo.hash,
427
+ index: utxo.index,
428
+ witnessUtxo: utxo.witnessUtxo,
429
+ });
430
+ });
412
431
  }
413
432
  else {
414
433
  const { pubkey, output } = Bitcoin.payments.p2tr({
@@ -452,7 +471,7 @@ class Client extends Client$1 {
452
471
  * @returns Prepared transaction with maximum sendable amount
453
472
  */
454
473
  prepareMaxTx(_a) {
455
- return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
474
+ return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, selectedUtxos, }) {
456
475
  try {
457
476
  const { psbt, utxos, inputs, maxAmount, fee } = yield this.sendMax({
458
477
  sender,
@@ -461,6 +480,7 @@ class Client extends Client$1 {
461
480
  feeRate,
462
481
  spendPendingUTXO,
463
482
  utxoSelectionPreferences,
483
+ selectedUtxos,
464
484
  });
465
485
  return {
466
486
  rawUnsignedTx: psbt.toBase64(),
@@ -486,7 +506,7 @@ class Client extends Client$1 {
486
506
  * @returns The raw unsigned transaction with enhanced error handling.
487
507
  */
488
508
  prepareTxEnhanced(_a) {
489
- return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, spendPendingUTXO = true, feeRate, utxoSelectionPreferences, }) {
509
+ return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, spendPendingUTXO = true, feeRate, utxoSelectionPreferences, selectedUtxos, }) {
490
510
  try {
491
511
  const { psbt, utxos, inputs } = yield this.buildTxEnhanced({
492
512
  sender,
@@ -496,6 +516,7 @@ class Client extends Client$1 {
496
516
  memo,
497
517
  spendPendingUTXO,
498
518
  utxoSelectionPreferences,
519
+ selectedUtxos,
499
520
  });
500
521
  return { rawUnsignedTx: psbt.toBase64(), utxos, inputs };
501
522
  }
@@ -628,7 +649,7 @@ class ClientKeystore extends Client {
628
649
  // Merge default preferences with caller-provided preferences
629
650
  const mergedUtxoSelectionPreferences = Object.assign({ minimizeFee: true, avoidDust: true, minimizeInputs: false }, params.utxoSelectionPreferences);
630
651
  // Prepare the transaction
631
- const { rawUnsignedTx } = yield this.prepareTxEnhanced(Object.assign(Object.assign({}, params), { sender: this.getAddress(fromAddressIndex), feeRate, utxoSelectionPreferences: mergedUtxoSelectionPreferences }));
652
+ const { rawUnsignedTx } = yield this.prepareTxEnhanced(Object.assign(Object.assign({}, params), { sender: this.getAddress(fromAddressIndex), feeRate, utxoSelectionPreferences: mergedUtxoSelectionPreferences, selectedUtxos: params.selectedUtxos }));
632
653
  // Build the PSBT
633
654
  const psbt = Bitcoin.Psbt.fromBase64(rawUnsignedTx);
634
655
  // Sign all inputs
@@ -667,6 +688,7 @@ class ClientKeystore extends Client {
667
688
  memo: params.memo,
668
689
  feeRate,
669
690
  utxoSelectionPreferences: params.utxoSelectionPreferences,
691
+ selectedUtxos: params.selectedUtxos,
670
692
  });
671
693
  const btcKeys = this.getBtcKeys(this.phrase, fromAddressIndex);
672
694
  psbt.signAllInputs(this.addressFormat === AddressFormat.P2WPKH
@@ -770,6 +792,50 @@ class ClientLedger extends Client {
770
792
  return txHash;
771
793
  });
772
794
  }
795
+ // Transfer max BTC from Ledger (sweep transaction)
796
+ transferMax(params) {
797
+ return __awaiter(this, void 0, void 0, function* () {
798
+ const app = yield this.getApp();
799
+ const fromAddressIndex = (params === null || params === void 0 ? void 0 : params.walletIndex) || 0;
800
+ const feeRate = params.feeRate || (yield this.getFeeRates())[FeeOption.Fast];
801
+ checkFeeBounds(this.feeBounds, feeRate);
802
+ const sender = yield this.getAddressAsync(fromAddressIndex);
803
+ const { rawUnsignedTx, inputs, maxAmount, fee } = yield this.prepareMaxTx({
804
+ sender,
805
+ recipient: params.recipient,
806
+ memo: params.memo,
807
+ feeRate,
808
+ utxoSelectionPreferences: params.utxoSelectionPreferences,
809
+ selectedUtxos: params.selectedUtxos,
810
+ });
811
+ const psbt = Bitcoin.Psbt.fromBase64(rawUnsignedTx);
812
+ const ledgerInputs = inputs.map(({ txHex, hash, index }) => {
813
+ if (!txHex) {
814
+ throw Error(`Missing 'txHex' for UTXO (txHash ${hash})`);
815
+ }
816
+ const utxoTx = Bitcoin.Transaction.fromHex(txHex);
817
+ const splittedTx = app.splitTransaction(txHex, utxoTx.hasWitnesses());
818
+ return [splittedTx, index, null, null];
819
+ });
820
+ const associatedKeysets = ledgerInputs.map(() => this.getFullDerivationPath(fromAddressIndex));
821
+ const unsignedHex = psbt.data.globalMap.unsignedTx.toBuffer().toString('hex');
822
+ const newTx = app.splitTransaction(unsignedHex, true);
823
+ const outputScriptHex = app.serializeTransactionOutputs(newTx).toString('hex');
824
+ const txHex = yield app.createPaymentTransaction({
825
+ inputs: ledgerInputs,
826
+ associatedKeysets,
827
+ outputScriptHex,
828
+ segwit: true,
829
+ useTrustedInputForSegwit: true,
830
+ additionals: [this.addressFormat === AddressFormat.P2TR ? 'bech32m' : 'bech32'],
831
+ });
832
+ const hash = yield this.broadcastTx(txHex);
833
+ if (!hash) {
834
+ throw Error('No Tx hash');
835
+ }
836
+ return { hash, maxAmount, fee };
837
+ });
838
+ }
773
839
  }
774
840
 
775
841
  export { AddressFormat, AssetBTC, BTCChain, BTC_DECIMAL, BTC_SATOSHI_SYMBOL, BTC_SYMBOL, BitgoProviders, BlockcypherDataProviders, ClientKeystore as Client, ClientLedger, HaskoinDataProviders, LOWER_FEE_BOUND, MIN_TX_FEE, SochainDataProviders, UPPER_FEE_BOUND, blockstreamExplorerProviders, defaultBTCParams, getPrefix, tapRootDerivationPaths, validateAddress };
package/lib/index.js CHANGED
@@ -315,7 +315,7 @@ class Client extends xchainUtxo.Client {
315
315
  * @returns Enhanced transaction build result with PSBT, UTXOs, and inputs
316
316
  */
317
317
  buildTxEnhanced(_a) {
318
- return __awaiter(this, arguments, void 0, function* ({ amount, recipient, memo, feeRate, sender, spendPendingUTXO = true, utxoSelectionPreferences, }) {
318
+ return __awaiter(this, arguments, void 0, function* ({ amount, recipient, memo, feeRate, sender, spendPendingUTXO = true, utxoSelectionPreferences, selectedUtxos, }) {
319
319
  try {
320
320
  // Comprehensive input validation
321
321
  this.validateTransactionInputs({
@@ -325,9 +325,16 @@ class Client extends xchainUtxo.Client {
325
325
  sender,
326
326
  feeRate,
327
327
  });
328
- // Get validated UTXOs
329
- const confirmedOnly = !spendPendingUTXO;
330
- const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
328
+ // Use provided UTXOs (coin control) or fetch from chain
329
+ let utxos;
330
+ if (selectedUtxos && selectedUtxos.length > 0) {
331
+ xchainUtxo.UtxoTransactionValidator.validateUtxoSet(selectedUtxos);
332
+ utxos = selectedUtxos;
333
+ }
334
+ else {
335
+ const confirmedOnly = !spendPendingUTXO;
336
+ utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
337
+ }
331
338
  const compiledMemo = memo ? this.compileMemo(memo) : null;
332
339
  const targetValue = amount.amount().toNumber();
333
340
  const extraOutputs = 1 + (compiledMemo ? 1 : 0); // recipient + optional memo (change calculated separately)
@@ -408,7 +415,7 @@ class Client extends xchainUtxo.Client {
408
415
  * @returns Transaction details with maximum sendable amount
409
416
  */
410
417
  sendMax(_a) {
411
- return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
418
+ return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, selectedUtxos, }) {
412
419
  try {
413
420
  // Basic validation (skip amount validation since we're calculating max)
414
421
  if (!(recipient === null || recipient === void 0 ? void 0 : recipient.trim())) {
@@ -421,20 +428,32 @@ class Client extends xchainUtxo.Client {
421
428
  throw xchainUtxo.UtxoError.invalidAddress(sender, this.network);
422
429
  }
423
430
  // Memo validation is handled by validateTransactionInputs
424
- // Get validated UTXOs
425
- const confirmedOnly = !spendPendingUTXO;
426
- const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
431
+ // Use provided UTXOs (coin control) or fetch from chain
432
+ let utxos;
433
+ if (selectedUtxos && selectedUtxos.length > 0) {
434
+ xchainUtxo.UtxoTransactionValidator.validateUtxoSet(selectedUtxos);
435
+ utxos = selectedUtxos;
436
+ }
437
+ else {
438
+ const confirmedOnly = !spendPendingUTXO;
439
+ utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
440
+ }
427
441
  // Calculate maximum sendable amount
428
442
  const maxCalc = this.calculateMaxSendableAmount(utxos, Math.ceil(feeRate), !!memo, utxoSelectionPreferences);
429
443
  const compiledMemo = memo ? this.compileMemo(memo) : null;
430
444
  const psbt = new Bitcoin__namespace.Psbt({ network: btcNetwork(this.network) });
431
445
  // Add inputs
432
446
  if (this.addressFormat === exports.AddressFormat.P2WPKH) {
433
- maxCalc.inputs.forEach((utxo) => psbt.addInput({
434
- hash: utxo.hash,
435
- index: utxo.index,
436
- witnessUtxo: utxo.witnessUtxo,
437
- }));
447
+ maxCalc.inputs.forEach((utxo) => {
448
+ if (!utxo.witnessUtxo) {
449
+ throw xchainUtxo.UtxoError.fromUnknown(new Error(`Missing witnessUtxo for UTXO ${utxo.hash}:${utxo.index}`), 'sendMax');
450
+ }
451
+ psbt.addInput({
452
+ hash: utxo.hash,
453
+ index: utxo.index,
454
+ witnessUtxo: utxo.witnessUtxo,
455
+ });
456
+ });
438
457
  }
439
458
  else {
440
459
  const { pubkey, output } = Bitcoin__namespace.payments.p2tr({
@@ -478,7 +497,7 @@ class Client extends xchainUtxo.Client {
478
497
  * @returns Prepared transaction with maximum sendable amount
479
498
  */
480
499
  prepareMaxTx(_a) {
481
- return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
500
+ return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, selectedUtxos, }) {
482
501
  try {
483
502
  const { psbt, utxos, inputs, maxAmount, fee } = yield this.sendMax({
484
503
  sender,
@@ -487,6 +506,7 @@ class Client extends xchainUtxo.Client {
487
506
  feeRate,
488
507
  spendPendingUTXO,
489
508
  utxoSelectionPreferences,
509
+ selectedUtxos,
490
510
  });
491
511
  return {
492
512
  rawUnsignedTx: psbt.toBase64(),
@@ -512,7 +532,7 @@ class Client extends xchainUtxo.Client {
512
532
  * @returns The raw unsigned transaction with enhanced error handling.
513
533
  */
514
534
  prepareTxEnhanced(_a) {
515
- return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, spendPendingUTXO = true, feeRate, utxoSelectionPreferences, }) {
535
+ return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, spendPendingUTXO = true, feeRate, utxoSelectionPreferences, selectedUtxos, }) {
516
536
  try {
517
537
  const { psbt, utxos, inputs } = yield this.buildTxEnhanced({
518
538
  sender,
@@ -522,6 +542,7 @@ class Client extends xchainUtxo.Client {
522
542
  memo,
523
543
  spendPendingUTXO,
524
544
  utxoSelectionPreferences,
545
+ selectedUtxos,
525
546
  });
526
547
  return { rawUnsignedTx: psbt.toBase64(), utxos, inputs };
527
548
  }
@@ -654,7 +675,7 @@ class ClientKeystore extends Client {
654
675
  // Merge default preferences with caller-provided preferences
655
676
  const mergedUtxoSelectionPreferences = Object.assign({ minimizeFee: true, avoidDust: true, minimizeInputs: false }, params.utxoSelectionPreferences);
656
677
  // Prepare the transaction
657
- const { rawUnsignedTx } = yield this.prepareTxEnhanced(Object.assign(Object.assign({}, params), { sender: this.getAddress(fromAddressIndex), feeRate, utxoSelectionPreferences: mergedUtxoSelectionPreferences }));
678
+ const { rawUnsignedTx } = yield this.prepareTxEnhanced(Object.assign(Object.assign({}, params), { sender: this.getAddress(fromAddressIndex), feeRate, utxoSelectionPreferences: mergedUtxoSelectionPreferences, selectedUtxos: params.selectedUtxos }));
658
679
  // Build the PSBT
659
680
  const psbt = Bitcoin__namespace.Psbt.fromBase64(rawUnsignedTx);
660
681
  // Sign all inputs
@@ -693,6 +714,7 @@ class ClientKeystore extends Client {
693
714
  memo: params.memo,
694
715
  feeRate,
695
716
  utxoSelectionPreferences: params.utxoSelectionPreferences,
717
+ selectedUtxos: params.selectedUtxos,
696
718
  });
697
719
  const btcKeys = this.getBtcKeys(this.phrase, fromAddressIndex);
698
720
  psbt.signAllInputs(this.addressFormat === exports.AddressFormat.P2WPKH
@@ -796,6 +818,50 @@ class ClientLedger extends Client {
796
818
  return txHash;
797
819
  });
798
820
  }
821
+ // Transfer max BTC from Ledger (sweep transaction)
822
+ transferMax(params) {
823
+ return __awaiter(this, void 0, void 0, function* () {
824
+ const app = yield this.getApp();
825
+ const fromAddressIndex = (params === null || params === void 0 ? void 0 : params.walletIndex) || 0;
826
+ const feeRate = params.feeRate || (yield this.getFeeRates())[xchainClient.FeeOption.Fast];
827
+ xchainClient.checkFeeBounds(this.feeBounds, feeRate);
828
+ const sender = yield this.getAddressAsync(fromAddressIndex);
829
+ const { rawUnsignedTx, inputs, maxAmount, fee } = yield this.prepareMaxTx({
830
+ sender,
831
+ recipient: params.recipient,
832
+ memo: params.memo,
833
+ feeRate,
834
+ utxoSelectionPreferences: params.utxoSelectionPreferences,
835
+ selectedUtxos: params.selectedUtxos,
836
+ });
837
+ const psbt = Bitcoin__namespace.Psbt.fromBase64(rawUnsignedTx);
838
+ const ledgerInputs = inputs.map(({ txHex, hash, index }) => {
839
+ if (!txHex) {
840
+ throw Error(`Missing 'txHex' for UTXO (txHash ${hash})`);
841
+ }
842
+ const utxoTx = Bitcoin__namespace.Transaction.fromHex(txHex);
843
+ const splittedTx = app.splitTransaction(txHex, utxoTx.hasWitnesses());
844
+ return [splittedTx, index, null, null];
845
+ });
846
+ const associatedKeysets = ledgerInputs.map(() => this.getFullDerivationPath(fromAddressIndex));
847
+ const unsignedHex = psbt.data.globalMap.unsignedTx.toBuffer().toString('hex');
848
+ const newTx = app.splitTransaction(unsignedHex, true);
849
+ const outputScriptHex = app.serializeTransactionOutputs(newTx).toString('hex');
850
+ const txHex = yield app.createPaymentTransaction({
851
+ inputs: ledgerInputs,
852
+ associatedKeysets,
853
+ outputScriptHex,
854
+ segwit: true,
855
+ useTrustedInputForSegwit: true,
856
+ additionals: [this.addressFormat === exports.AddressFormat.P2TR ? 'bech32m' : 'bech32'],
857
+ });
858
+ const hash = yield this.broadcastTx(txHex);
859
+ if (!hash) {
860
+ throw Error('No Tx hash');
861
+ }
862
+ return { hash, maxAmount, fee };
863
+ });
864
+ }
799
865
  }
800
866
 
801
867
  exports.AssetBTC = AssetBTC;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xchainjs/xchain-bitcoin",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Custom Bitcoin client and utilities used by XChainJS clients",
5
5
  "keywords": [
6
6
  "XChain",
@@ -39,7 +39,7 @@
39
39
  "@xchainjs/xchain-client": "2.0.10",
40
40
  "@xchainjs/xchain-crypto": "1.0.6",
41
41
  "@xchainjs/xchain-util": "2.0.5",
42
- "@xchainjs/xchain-utxo": "2.1.0",
42
+ "@xchainjs/xchain-utxo": "2.2.0",
43
43
  "@xchainjs/xchain-utxo-providers": "2.0.10",
44
44
  "bitcoinjs-lib": "^6.1.7",
45
45
  "coinselect": "3.1.12",