@xchainjs/xchain-doge 2.0.9 → 2.1.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
@@ -1,6 +1,6 @@
1
1
  import { AssetInfo, FeeRate } from '@xchainjs/xchain-client';
2
2
  import { Address } from '@xchainjs/xchain-util';
3
- import { Client as UTXOClient, PreparedTx, TxParams, UTXO, UtxoClientParams } from '@xchainjs/xchain-utxo';
3
+ import { Client as UTXOClient, PreparedTx, TxParams, UTXO, UtxoClientParams, UtxoSelectionPreferences } from '@xchainjs/xchain-utxo';
4
4
  import * as Dogecoin from 'bitcoinjs-lib';
5
5
  import { LedgerTxInfo, LedgerTxInfoParams } from './types/ledger';
6
6
  /**
@@ -62,6 +62,7 @@ declare abstract class Client extends UTXOClient {
62
62
  * Asynchronously prepares a transaction for transfer.
63
63
  *
64
64
  * Builds a transaction (PSBT) with the specified transfer options.
65
+ * @deprecated Use `prepareTxEnhanced` instead for better UTXO selection and error handling.
65
66
  * @param {TxParams & { sender: Address; feeRate: FeeRate; spendPendingUTXO?: boolean }} params The transfer options including sender address, fee rate, and optional flag for spending pending UTXOs.
66
67
  * @returns {Promise<PreparedTx>} A promise that resolves to the raw unsigned transaction (PSBT).
67
68
  */
@@ -89,5 +90,59 @@ declare abstract class Client extends UTXOClient {
89
90
  * @returns {number} The calculated transaction fee.
90
91
  */
91
92
  protected getFeeFromUtxos(inputs: UTXO[], feeRate: FeeRate, data?: Buffer | null): number;
93
+ /**
94
+ * Build transaction with enhanced UTXO selection
95
+ * Note: Doge uses legacy P2PKH addresses (nonWitnessUtxo)
96
+ */
97
+ buildTxEnhanced({ amount, recipient, memo, feeRate, sender, spendPendingUTXO, utxoSelectionPreferences, }: TxParams & {
98
+ feeRate: FeeRate;
99
+ sender: Address;
100
+ spendPendingUTXO?: boolean;
101
+ utxoSelectionPreferences?: UtxoSelectionPreferences;
102
+ }): Promise<{
103
+ psbt: Dogecoin.Psbt;
104
+ utxos: UTXO[];
105
+ inputs: UTXO[];
106
+ }>;
107
+ /**
108
+ * Prepare transaction with enhanced UTXO selection
109
+ */
110
+ prepareTxEnhanced({ sender, memo, amount, recipient, spendPendingUTXO, feeRate, utxoSelectionPreferences, }: TxParams & {
111
+ sender: Address;
112
+ feeRate: FeeRate;
113
+ spendPendingUTXO?: boolean;
114
+ utxoSelectionPreferences?: UtxoSelectionPreferences;
115
+ }): Promise<PreparedTx>;
116
+ /**
117
+ * Send maximum possible amount (sweep)
118
+ */
119
+ sendMax({ sender, recipient, memo, feeRate, spendPendingUTXO, utxoSelectionPreferences, }: {
120
+ sender: Address;
121
+ recipient: Address;
122
+ memo?: string;
123
+ feeRate: FeeRate;
124
+ spendPendingUTXO?: boolean;
125
+ utxoSelectionPreferences?: UtxoSelectionPreferences;
126
+ }): Promise<{
127
+ psbt: Dogecoin.Psbt;
128
+ utxos: UTXO[];
129
+ inputs: UTXO[];
130
+ maxAmount: number;
131
+ fee: number;
132
+ }>;
133
+ /**
134
+ * Prepare max send transaction
135
+ */
136
+ prepareMaxTx({ sender, recipient, memo, feeRate, spendPendingUTXO, utxoSelectionPreferences, }: {
137
+ sender: Address;
138
+ recipient: Address;
139
+ memo?: string;
140
+ feeRate: FeeRate;
141
+ spendPendingUTXO?: boolean;
142
+ utxoSelectionPreferences?: UtxoSelectionPreferences;
143
+ }): Promise<PreparedTx & {
144
+ maxAmount: number;
145
+ fee: number;
146
+ }>;
92
147
  }
93
148
  export { Client };
@@ -1,6 +1,6 @@
1
1
  import { FeeRate, TxHash } from '@xchainjs/xchain-client';
2
2
  import { Address } from '@xchainjs/xchain-util';
3
- import { TxParams } from '@xchainjs/xchain-utxo';
3
+ import { TxParams, UtxoSelectionPreferences } from '@xchainjs/xchain-utxo';
4
4
  import { Client } from './client';
5
5
  /**
6
6
  * Custom Doge client extended to support keystore functionality
@@ -44,11 +44,36 @@ declare class ClientKeystore extends Client {
44
44
  * Asynchronously transfers Dogecoin.
45
45
  *
46
46
  * Builds, signs, and broadcasts a Dogecoin transaction with the specified parameters.
47
- * @param {TxParams & { feeRate?: FeeRate }} params The transfer parameters including transaction details and optional fee rate.
48
- * @returns {TxHash} A promise that resolves to the transaction hash once the transfer is completed.
47
+ *
48
+ * @param {Object} params The transfer parameters.
49
+ * @returns {Promise<TxHash>} The transaction hash.
49
50
  */
50
51
  transfer(params: TxParams & {
51
52
  feeRate?: FeeRate;
53
+ utxoSelectionPreferences?: UtxoSelectionPreferences;
52
54
  }): Promise<TxHash>;
55
+ /**
56
+ * Transfer the maximum amount of Dogecoin (sweep).
57
+ *
58
+ * Calculates the maximum sendable amount after fees, signs, and broadcasts the transaction.
59
+ * @param {Object} params The transfer parameters.
60
+ * @param {string} params.recipient The recipient address.
61
+ * @param {string} [params.memo] Optional memo for the transaction.
62
+ * @param {FeeRate} [params.feeRate] Optional fee rate. Defaults to 'fast' rate.
63
+ * @param {number} [params.walletIndex] Optional wallet index. Defaults to 0.
64
+ * @param {UtxoSelectionPreferences} [params.utxoSelectionPreferences] Optional UTXO selection preferences.
65
+ * @returns {Promise<{ hash: TxHash; maxAmount: number; fee: number }>} The transaction hash, amount sent, and fee.
66
+ */
67
+ transferMax(params: {
68
+ recipient: Address;
69
+ memo?: string;
70
+ feeRate?: FeeRate;
71
+ walletIndex?: number;
72
+ utxoSelectionPreferences?: UtxoSelectionPreferences;
73
+ }): Promise<{
74
+ hash: TxHash;
75
+ maxAmount: number;
76
+ fee: number;
77
+ }>;
53
78
  }
54
79
  export { ClientKeystore };
package/lib/index.esm.js CHANGED
@@ -4,7 +4,7 @@ import { getSeed } from '@xchainjs/xchain-crypto';
4
4
  import * as Dogecoin from 'bitcoinjs-lib';
5
5
  import { ECPairFactory } from 'ecpair';
6
6
  import { HDKey } from '@scure/bip32';
7
- import { toBitcoinJS, Client as Client$1 } from '@xchainjs/xchain-utxo';
7
+ import { toBitcoinJS, Client as Client$1, UtxoError } from '@xchainjs/xchain-utxo';
8
8
  import accumulative from 'coinselect/accumulative.js';
9
9
  import { AssetType } from '@xchainjs/xchain-util';
10
10
  import { SochainProvider, SochainNetwork, BlockcypherProvider, BlockcypherNetwork, BitgoProvider } from '@xchainjs/xchain-utxo-providers';
@@ -340,6 +340,7 @@ class Client extends Client$1 {
340
340
  * Asynchronously prepares a transaction for transfer.
341
341
  *
342
342
  * Builds a transaction (PSBT) with the specified transfer options.
343
+ * @deprecated Use `prepareTxEnhanced` instead for better UTXO selection and error handling.
343
344
  * @param {TxParams & { sender: Address; feeRate: FeeRate; spendPendingUTXO?: boolean }} params The transfer options including sender address, fee rate, and optional flag for spending pending UTXOs.
344
345
  * @returns {Promise<PreparedTx>} A promise that resolves to the raw unsigned transaction (PSBT).
345
346
  */
@@ -398,6 +399,167 @@ class Client extends Client$1 {
398
399
  // Ensure the fee is not less than the minimum transaction fee
399
400
  return fee > MIN_TX_FEE ? fee : MIN_TX_FEE;
400
401
  }
402
+ // ==================== Enhanced Transaction Methods ====================
403
+ /**
404
+ * Build transaction with enhanced UTXO selection
405
+ * Note: Doge uses legacy P2PKH addresses (nonWitnessUtxo)
406
+ */
407
+ buildTxEnhanced(_a) {
408
+ return __awaiter(this, arguments, void 0, function* ({ amount, recipient, memo, feeRate, sender, spendPendingUTXO = true, utxoSelectionPreferences, }) {
409
+ try {
410
+ this.validateTransactionInputs({
411
+ amount,
412
+ recipient,
413
+ memo,
414
+ sender,
415
+ feeRate,
416
+ });
417
+ const confirmedOnly = !spendPendingUTXO;
418
+ const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
419
+ const compiledMemo = memo ? this.compileMemo(memo) : null;
420
+ const targetValue = amount.amount().toNumber();
421
+ const extraOutputs = 1 + (compiledMemo ? 1 : 0);
422
+ const selectionResult = this.selectUtxosForTransaction(utxos, targetValue, Math.ceil(feeRate), extraOutputs, utxoSelectionPreferences);
423
+ const psbt = new Dogecoin.Psbt({ network: dogeNetwork(this.network) });
424
+ psbt.setMaximumFeeRate(7500000);
425
+ // Add inputs - Doge uses nonWitnessUtxo (legacy P2PKH)
426
+ for (const utxo of selectionResult.inputs) {
427
+ psbt.addInput({
428
+ hash: utxo.hash,
429
+ index: utxo.index,
430
+ nonWitnessUtxo: Buffer.from(utxo.txHex || '', 'hex'),
431
+ });
432
+ }
433
+ // Add recipient output
434
+ psbt.addOutput({
435
+ address: recipient,
436
+ value: targetValue,
437
+ });
438
+ // Add change output if needed
439
+ if (selectionResult.changeAmount > 0) {
440
+ psbt.addOutput({
441
+ address: sender,
442
+ value: selectionResult.changeAmount,
443
+ });
444
+ }
445
+ // Add memo output if present
446
+ if (compiledMemo) {
447
+ psbt.addOutput({ script: compiledMemo, value: 0 });
448
+ }
449
+ return { psbt, utxos, inputs: selectionResult.inputs };
450
+ }
451
+ catch (error) {
452
+ if (UtxoError.isUtxoError(error)) {
453
+ throw error;
454
+ }
455
+ throw UtxoError.fromUnknown(error, 'buildTxEnhanced');
456
+ }
457
+ });
458
+ }
459
+ /**
460
+ * Prepare transaction with enhanced UTXO selection
461
+ */
462
+ prepareTxEnhanced(_a) {
463
+ return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, spendPendingUTXO = true, feeRate, utxoSelectionPreferences, }) {
464
+ try {
465
+ const { psbt, utxos, inputs } = yield this.buildTxEnhanced({
466
+ sender,
467
+ recipient,
468
+ amount,
469
+ feeRate,
470
+ memo,
471
+ spendPendingUTXO,
472
+ utxoSelectionPreferences,
473
+ });
474
+ return { rawUnsignedTx: psbt.toBase64(), utxos, inputs };
475
+ }
476
+ catch (error) {
477
+ if (UtxoError.isUtxoError(error)) {
478
+ throw error;
479
+ }
480
+ throw UtxoError.fromUnknown(error, 'prepareTxEnhanced');
481
+ }
482
+ });
483
+ }
484
+ /**
485
+ * Send maximum possible amount (sweep)
486
+ */
487
+ sendMax(_a) {
488
+ return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
489
+ try {
490
+ if (!this.validateAddress(recipient)) {
491
+ throw UtxoError.invalidAddress(recipient, this.network);
492
+ }
493
+ if (!this.validateAddress(sender)) {
494
+ throw UtxoError.invalidAddress(sender, this.network);
495
+ }
496
+ const confirmedOnly = !spendPendingUTXO;
497
+ const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
498
+ const maxCalc = this.calculateMaxSendableAmount(utxos, Math.ceil(feeRate), !!memo, utxoSelectionPreferences);
499
+ const compiledMemo = memo ? this.compileMemo(memo) : null;
500
+ const psbt = new Dogecoin.Psbt({ network: dogeNetwork(this.network) });
501
+ psbt.setMaximumFeeRate(7500000);
502
+ // Add inputs - Doge uses nonWitnessUtxo
503
+ for (const utxo of maxCalc.inputs) {
504
+ psbt.addInput({
505
+ hash: utxo.hash,
506
+ index: utxo.index,
507
+ nonWitnessUtxo: Buffer.from(utxo.txHex || '', 'hex'),
508
+ });
509
+ }
510
+ psbt.addOutput({
511
+ address: recipient,
512
+ value: maxCalc.amount,
513
+ });
514
+ if (compiledMemo) {
515
+ psbt.addOutput({ script: compiledMemo, value: 0 });
516
+ }
517
+ return {
518
+ psbt,
519
+ utxos,
520
+ inputs: maxCalc.inputs,
521
+ maxAmount: maxCalc.amount,
522
+ fee: maxCalc.fee,
523
+ };
524
+ }
525
+ catch (error) {
526
+ if (UtxoError.isUtxoError(error)) {
527
+ throw error;
528
+ }
529
+ throw UtxoError.fromUnknown(error, 'sendMax');
530
+ }
531
+ });
532
+ }
533
+ /**
534
+ * Prepare max send transaction
535
+ */
536
+ prepareMaxTx(_a) {
537
+ return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
538
+ try {
539
+ const { psbt, utxos, inputs, maxAmount, fee } = yield this.sendMax({
540
+ sender,
541
+ recipient,
542
+ memo,
543
+ feeRate,
544
+ spendPendingUTXO,
545
+ utxoSelectionPreferences,
546
+ });
547
+ return {
548
+ rawUnsignedTx: psbt.toBase64(),
549
+ utxos,
550
+ inputs,
551
+ maxAmount,
552
+ fee,
553
+ };
554
+ }
555
+ catch (error) {
556
+ if (UtxoError.isUtxoError(error)) {
557
+ throw error;
558
+ }
559
+ throw UtxoError.fromUnknown(error, 'prepareMaxTx');
560
+ }
561
+ });
562
+ }
401
563
  }
402
564
 
403
565
  const ECPair = ECPairFactory(ecc);
@@ -474,33 +636,60 @@ class ClientKeystore extends Client {
474
636
  * Asynchronously transfers Dogecoin.
475
637
  *
476
638
  * Builds, signs, and broadcasts a Dogecoin transaction with the specified parameters.
477
- * @param {TxParams & { feeRate?: FeeRate }} params The transfer parameters including transaction details and optional fee rate.
478
- * @returns {TxHash} A promise that resolves to the transaction hash once the transfer is completed.
639
+ *
640
+ * @param {Object} params The transfer parameters.
641
+ * @returns {Promise<TxHash>} The transaction hash.
479
642
  */
480
643
  transfer(params) {
481
644
  return __awaiter(this, void 0, void 0, function* () {
482
- // Determine the fee rate for the transaction, using provided fee rate or fetching it from the network
483
645
  const feeRate = params.feeRate || (yield this.getFeeRates())[FeeOption.Fast];
484
- // Check if the fee rate is within the specified fee bounds
485
646
  checkFeeBounds(this.feeBounds, feeRate);
486
- // Get the index of the sender's address or use the default index (0)
487
647
  const fromAddressIndex = (params === null || params === void 0 ? void 0 : params.walletIndex) || 0;
488
- // Prepare the transaction by building it with the specified parameters
489
- const { rawUnsignedTx } = yield this.prepareTx(Object.assign(Object.assign({}, params), { feeRate, sender: yield this.getAddressAsync(fromAddressIndex) }));
490
- // Get the Dogecoin keys for signing the transaction
648
+ const sender = yield this.getAddressAsync(fromAddressIndex);
491
649
  const dogeKeys = this.getDogeKeys(this.phrase, fromAddressIndex);
492
- // Create a Partially Signed Bitcoin Transaction (PSBT) from the raw unsigned transaction
650
+ const mergedPreferences = Object.assign({ minimizeFee: true, avoidDust: true, minimizeInputs: false }, params.utxoSelectionPreferences);
651
+ const { rawUnsignedTx } = yield this.prepareTxEnhanced(Object.assign(Object.assign({}, params), { feeRate,
652
+ sender, utxoSelectionPreferences: mergedPreferences }));
493
653
  const psbt = Dogecoin.Psbt.fromBase64(rawUnsignedTx, { maximumFeeRate: 7500000 });
494
- // Sign all inputs of the transaction with the Dogecoin keys
495
654
  psbt.signAllInputs(dogeKeys);
496
- // Finalize all inputs of the transaction
497
655
  psbt.finalizeAllInputs();
498
- // Extract the signed transaction and format it to hexadecimal
499
656
  const txHex = psbt.extractTransaction().toHex();
500
- // Broadcast the signed transaction to the Dogecoin network and return the transaction hash
501
657
  return yield this.roundRobinBroadcastTx(txHex);
502
658
  });
503
659
  }
660
+ /**
661
+ * Transfer the maximum amount of Dogecoin (sweep).
662
+ *
663
+ * Calculates the maximum sendable amount after fees, signs, and broadcasts the transaction.
664
+ * @param {Object} params The transfer parameters.
665
+ * @param {string} params.recipient The recipient address.
666
+ * @param {string} [params.memo] Optional memo for the transaction.
667
+ * @param {FeeRate} [params.feeRate] Optional fee rate. Defaults to 'fast' rate.
668
+ * @param {number} [params.walletIndex] Optional wallet index. Defaults to 0.
669
+ * @param {UtxoSelectionPreferences} [params.utxoSelectionPreferences] Optional UTXO selection preferences.
670
+ * @returns {Promise<{ hash: TxHash; maxAmount: number; fee: number }>} The transaction hash, amount sent, and fee.
671
+ */
672
+ transferMax(params) {
673
+ return __awaiter(this, void 0, void 0, function* () {
674
+ const feeRate = params.feeRate || (yield this.getFeeRates())[FeeOption.Fast];
675
+ checkFeeBounds(this.feeBounds, feeRate);
676
+ const fromAddressIndex = params.walletIndex || 0;
677
+ const sender = yield this.getAddressAsync(fromAddressIndex);
678
+ const { psbt, maxAmount, fee } = yield this.sendMax({
679
+ sender,
680
+ recipient: params.recipient,
681
+ memo: params.memo,
682
+ feeRate,
683
+ utxoSelectionPreferences: params.utxoSelectionPreferences,
684
+ });
685
+ const dogeKeys = this.getDogeKeys(this.phrase, fromAddressIndex);
686
+ psbt.signAllInputs(dogeKeys);
687
+ psbt.finalizeAllInputs();
688
+ const txHex = psbt.extractTransaction().toHex();
689
+ const hash = yield this.roundRobinBroadcastTx(txHex);
690
+ return { hash, maxAmount, fee };
691
+ });
692
+ }
504
693
  }
505
694
 
506
695
  /**
package/lib/index.js CHANGED
@@ -367,6 +367,7 @@ class Client extends xchainUtxo.Client {
367
367
  * Asynchronously prepares a transaction for transfer.
368
368
  *
369
369
  * Builds a transaction (PSBT) with the specified transfer options.
370
+ * @deprecated Use `prepareTxEnhanced` instead for better UTXO selection and error handling.
370
371
  * @param {TxParams & { sender: Address; feeRate: FeeRate; spendPendingUTXO?: boolean }} params The transfer options including sender address, fee rate, and optional flag for spending pending UTXOs.
371
372
  * @returns {Promise<PreparedTx>} A promise that resolves to the raw unsigned transaction (PSBT).
372
373
  */
@@ -425,6 +426,167 @@ class Client extends xchainUtxo.Client {
425
426
  // Ensure the fee is not less than the minimum transaction fee
426
427
  return fee > MIN_TX_FEE ? fee : MIN_TX_FEE;
427
428
  }
429
+ // ==================== Enhanced Transaction Methods ====================
430
+ /**
431
+ * Build transaction with enhanced UTXO selection
432
+ * Note: Doge uses legacy P2PKH addresses (nonWitnessUtxo)
433
+ */
434
+ buildTxEnhanced(_a) {
435
+ return __awaiter(this, arguments, void 0, function* ({ amount, recipient, memo, feeRate, sender, spendPendingUTXO = true, utxoSelectionPreferences, }) {
436
+ try {
437
+ this.validateTransactionInputs({
438
+ amount,
439
+ recipient,
440
+ memo,
441
+ sender,
442
+ feeRate,
443
+ });
444
+ const confirmedOnly = !spendPendingUTXO;
445
+ const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
446
+ const compiledMemo = memo ? this.compileMemo(memo) : null;
447
+ const targetValue = amount.amount().toNumber();
448
+ const extraOutputs = 1 + (compiledMemo ? 1 : 0);
449
+ const selectionResult = this.selectUtxosForTransaction(utxos, targetValue, Math.ceil(feeRate), extraOutputs, utxoSelectionPreferences);
450
+ const psbt = new Dogecoin__namespace.Psbt({ network: dogeNetwork(this.network) });
451
+ psbt.setMaximumFeeRate(7500000);
452
+ // Add inputs - Doge uses nonWitnessUtxo (legacy P2PKH)
453
+ for (const utxo of selectionResult.inputs) {
454
+ psbt.addInput({
455
+ hash: utxo.hash,
456
+ index: utxo.index,
457
+ nonWitnessUtxo: Buffer.from(utxo.txHex || '', 'hex'),
458
+ });
459
+ }
460
+ // Add recipient output
461
+ psbt.addOutput({
462
+ address: recipient,
463
+ value: targetValue,
464
+ });
465
+ // Add change output if needed
466
+ if (selectionResult.changeAmount > 0) {
467
+ psbt.addOutput({
468
+ address: sender,
469
+ value: selectionResult.changeAmount,
470
+ });
471
+ }
472
+ // Add memo output if present
473
+ if (compiledMemo) {
474
+ psbt.addOutput({ script: compiledMemo, value: 0 });
475
+ }
476
+ return { psbt, utxos, inputs: selectionResult.inputs };
477
+ }
478
+ catch (error) {
479
+ if (xchainUtxo.UtxoError.isUtxoError(error)) {
480
+ throw error;
481
+ }
482
+ throw xchainUtxo.UtxoError.fromUnknown(error, 'buildTxEnhanced');
483
+ }
484
+ });
485
+ }
486
+ /**
487
+ * Prepare transaction with enhanced UTXO selection
488
+ */
489
+ prepareTxEnhanced(_a) {
490
+ return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, spendPendingUTXO = true, feeRate, utxoSelectionPreferences, }) {
491
+ try {
492
+ const { psbt, utxos, inputs } = yield this.buildTxEnhanced({
493
+ sender,
494
+ recipient,
495
+ amount,
496
+ feeRate,
497
+ memo,
498
+ spendPendingUTXO,
499
+ utxoSelectionPreferences,
500
+ });
501
+ return { rawUnsignedTx: psbt.toBase64(), utxos, inputs };
502
+ }
503
+ catch (error) {
504
+ if (xchainUtxo.UtxoError.isUtxoError(error)) {
505
+ throw error;
506
+ }
507
+ throw xchainUtxo.UtxoError.fromUnknown(error, 'prepareTxEnhanced');
508
+ }
509
+ });
510
+ }
511
+ /**
512
+ * Send maximum possible amount (sweep)
513
+ */
514
+ sendMax(_a) {
515
+ return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
516
+ try {
517
+ if (!this.validateAddress(recipient)) {
518
+ throw xchainUtxo.UtxoError.invalidAddress(recipient, this.network);
519
+ }
520
+ if (!this.validateAddress(sender)) {
521
+ throw xchainUtxo.UtxoError.invalidAddress(sender, this.network);
522
+ }
523
+ const confirmedOnly = !spendPendingUTXO;
524
+ const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
525
+ const maxCalc = this.calculateMaxSendableAmount(utxos, Math.ceil(feeRate), !!memo, utxoSelectionPreferences);
526
+ const compiledMemo = memo ? this.compileMemo(memo) : null;
527
+ const psbt = new Dogecoin__namespace.Psbt({ network: dogeNetwork(this.network) });
528
+ psbt.setMaximumFeeRate(7500000);
529
+ // Add inputs - Doge uses nonWitnessUtxo
530
+ for (const utxo of maxCalc.inputs) {
531
+ psbt.addInput({
532
+ hash: utxo.hash,
533
+ index: utxo.index,
534
+ nonWitnessUtxo: Buffer.from(utxo.txHex || '', 'hex'),
535
+ });
536
+ }
537
+ psbt.addOutput({
538
+ address: recipient,
539
+ value: maxCalc.amount,
540
+ });
541
+ if (compiledMemo) {
542
+ psbt.addOutput({ script: compiledMemo, value: 0 });
543
+ }
544
+ return {
545
+ psbt,
546
+ utxos,
547
+ inputs: maxCalc.inputs,
548
+ maxAmount: maxCalc.amount,
549
+ fee: maxCalc.fee,
550
+ };
551
+ }
552
+ catch (error) {
553
+ if (xchainUtxo.UtxoError.isUtxoError(error)) {
554
+ throw error;
555
+ }
556
+ throw xchainUtxo.UtxoError.fromUnknown(error, 'sendMax');
557
+ }
558
+ });
559
+ }
560
+ /**
561
+ * Prepare max send transaction
562
+ */
563
+ prepareMaxTx(_a) {
564
+ return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
565
+ try {
566
+ const { psbt, utxos, inputs, maxAmount, fee } = yield this.sendMax({
567
+ sender,
568
+ recipient,
569
+ memo,
570
+ feeRate,
571
+ spendPendingUTXO,
572
+ utxoSelectionPreferences,
573
+ });
574
+ return {
575
+ rawUnsignedTx: psbt.toBase64(),
576
+ utxos,
577
+ inputs,
578
+ maxAmount,
579
+ fee,
580
+ };
581
+ }
582
+ catch (error) {
583
+ if (xchainUtxo.UtxoError.isUtxoError(error)) {
584
+ throw error;
585
+ }
586
+ throw xchainUtxo.UtxoError.fromUnknown(error, 'prepareMaxTx');
587
+ }
588
+ });
589
+ }
428
590
  }
429
591
 
430
592
  const ECPair = ecpair.ECPairFactory(ecc__namespace);
@@ -501,33 +663,60 @@ class ClientKeystore extends Client {
501
663
  * Asynchronously transfers Dogecoin.
502
664
  *
503
665
  * Builds, signs, and broadcasts a Dogecoin transaction with the specified parameters.
504
- * @param {TxParams & { feeRate?: FeeRate }} params The transfer parameters including transaction details and optional fee rate.
505
- * @returns {TxHash} A promise that resolves to the transaction hash once the transfer is completed.
666
+ *
667
+ * @param {Object} params The transfer parameters.
668
+ * @returns {Promise<TxHash>} The transaction hash.
506
669
  */
507
670
  transfer(params) {
508
671
  return __awaiter(this, void 0, void 0, function* () {
509
- // Determine the fee rate for the transaction, using provided fee rate or fetching it from the network
510
672
  const feeRate = params.feeRate || (yield this.getFeeRates())[xchainClient.FeeOption.Fast];
511
- // Check if the fee rate is within the specified fee bounds
512
673
  xchainClient.checkFeeBounds(this.feeBounds, feeRate);
513
- // Get the index of the sender's address or use the default index (0)
514
674
  const fromAddressIndex = (params === null || params === void 0 ? void 0 : params.walletIndex) || 0;
515
- // Prepare the transaction by building it with the specified parameters
516
- const { rawUnsignedTx } = yield this.prepareTx(Object.assign(Object.assign({}, params), { feeRate, sender: yield this.getAddressAsync(fromAddressIndex) }));
517
- // Get the Dogecoin keys for signing the transaction
675
+ const sender = yield this.getAddressAsync(fromAddressIndex);
518
676
  const dogeKeys = this.getDogeKeys(this.phrase, fromAddressIndex);
519
- // Create a Partially Signed Bitcoin Transaction (PSBT) from the raw unsigned transaction
677
+ const mergedPreferences = Object.assign({ minimizeFee: true, avoidDust: true, minimizeInputs: false }, params.utxoSelectionPreferences);
678
+ const { rawUnsignedTx } = yield this.prepareTxEnhanced(Object.assign(Object.assign({}, params), { feeRate,
679
+ sender, utxoSelectionPreferences: mergedPreferences }));
520
680
  const psbt = Dogecoin__namespace.Psbt.fromBase64(rawUnsignedTx, { maximumFeeRate: 7500000 });
521
- // Sign all inputs of the transaction with the Dogecoin keys
522
681
  psbt.signAllInputs(dogeKeys);
523
- // Finalize all inputs of the transaction
524
682
  psbt.finalizeAllInputs();
525
- // Extract the signed transaction and format it to hexadecimal
526
683
  const txHex = psbt.extractTransaction().toHex();
527
- // Broadcast the signed transaction to the Dogecoin network and return the transaction hash
528
684
  return yield this.roundRobinBroadcastTx(txHex);
529
685
  });
530
686
  }
687
+ /**
688
+ * Transfer the maximum amount of Dogecoin (sweep).
689
+ *
690
+ * Calculates the maximum sendable amount after fees, signs, and broadcasts the transaction.
691
+ * @param {Object} params The transfer parameters.
692
+ * @param {string} params.recipient The recipient address.
693
+ * @param {string} [params.memo] Optional memo for the transaction.
694
+ * @param {FeeRate} [params.feeRate] Optional fee rate. Defaults to 'fast' rate.
695
+ * @param {number} [params.walletIndex] Optional wallet index. Defaults to 0.
696
+ * @param {UtxoSelectionPreferences} [params.utxoSelectionPreferences] Optional UTXO selection preferences.
697
+ * @returns {Promise<{ hash: TxHash; maxAmount: number; fee: number }>} The transaction hash, amount sent, and fee.
698
+ */
699
+ transferMax(params) {
700
+ return __awaiter(this, void 0, void 0, function* () {
701
+ const feeRate = params.feeRate || (yield this.getFeeRates())[xchainClient.FeeOption.Fast];
702
+ xchainClient.checkFeeBounds(this.feeBounds, feeRate);
703
+ const fromAddressIndex = params.walletIndex || 0;
704
+ const sender = yield this.getAddressAsync(fromAddressIndex);
705
+ const { psbt, maxAmount, fee } = yield this.sendMax({
706
+ sender,
707
+ recipient: params.recipient,
708
+ memo: params.memo,
709
+ feeRate,
710
+ utxoSelectionPreferences: params.utxoSelectionPreferences,
711
+ });
712
+ const dogeKeys = this.getDogeKeys(this.phrase, fromAddressIndex);
713
+ psbt.signAllInputs(dogeKeys);
714
+ psbt.finalizeAllInputs();
715
+ const txHex = psbt.extractTransaction().toHex();
716
+ const hash = yield this.roundRobinBroadcastTx(txHex);
717
+ return { hash, maxAmount, fee };
718
+ });
719
+ }
531
720
  }
532
721
 
533
722
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xchainjs/xchain-doge",
3
- "version": "2.0.9",
3
+ "version": "2.1.0",
4
4
  "description": "Custom Doge client and utilities used by XChain clients",
5
5
  "keywords": [
6
6
  "Xchain",
@@ -36,18 +36,18 @@
36
36
  "@bitcoin-js/tiny-secp256k1-asmjs": "^2.2.3",
37
37
  "@ledgerhq/hw-app-btc": "^10.9.0",
38
38
  "@scure/bip32": "^1.7.0",
39
- "@xchainjs/xchain-client": "2.0.9",
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.0.9",
43
- "@xchainjs/xchain-utxo-providers": "2.0.9",
42
+ "@xchainjs/xchain-utxo": "2.1.0",
43
+ "@xchainjs/xchain-utxo-providers": "2.0.10",
44
44
  "bitcoinjs-lib": "^6.1.7",
45
45
  "coinselect": "3.1.12",
46
46
  "ecpair": "2.1.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@ledgerhq/hw-transport-node-hid": "^6.28.6",
50
- "axios": "1.12.1",
50
+ "axios": "1.13.5",
51
51
  "axios-mock-adapter": "^2.1.0"
52
52
  },
53
53
  "publishConfig": {