@xchainjs/xchain-dash 2.0.10 → 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 +26 -1
- package/lib/clientKeystore.d.ts +26 -2
- package/lib/index.esm.js +181 -3
- package/lib/index.js +180 -2
- package/package.json +2 -2
package/lib/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AssetInfo, FeeRate, TxHistoryParams } from '@xchainjs/xchain-client';
|
|
2
2
|
import { Address } from '@xchainjs/xchain-util';
|
|
3
|
-
import { Balance, Client as UTXOClient, Tx, TxParams, TxsPage, UTXO, UtxoClientParams } from '@xchainjs/xchain-utxo';
|
|
3
|
+
import { Balance, Client as UTXOClient, PreparedTx, Tx, TxParams, TxsPage, UTXO, UtxoClientParams, UtxoSelectionPreferences } from '@xchainjs/xchain-utxo';
|
|
4
4
|
import { DashPreparedTx, NodeAuth, NodeUrls } from './types';
|
|
5
5
|
/**
|
|
6
6
|
* Default parameters for the DASH client.
|
|
@@ -59,6 +59,7 @@ declare abstract class Client extends UTXOClient {
|
|
|
59
59
|
private insightTxToXChainTx;
|
|
60
60
|
/**
|
|
61
61
|
* Asynchronously prepares a transaction for sending assets.
|
|
62
|
+
* @deprecated Use `prepareTxEnhanced` instead for better UTXO selection and error handling.
|
|
62
63
|
* @param {TxParams&Address&FeeRate} params - Parameters for the transaction preparation.
|
|
63
64
|
* @returns {string} A promise resolving to the prepared transaction data.
|
|
64
65
|
*/
|
|
@@ -80,5 +81,29 @@ declare abstract class Client extends UTXOClient {
|
|
|
80
81
|
* @returns {number} The calculated transaction fee amount.
|
|
81
82
|
*/
|
|
82
83
|
protected getFeeFromUtxos(inputs: UTXO[], feeRate: FeeRate, data?: Buffer | null): number;
|
|
84
|
+
/**
|
|
85
|
+
* Prepare transaction with enhanced UTXO selection.
|
|
86
|
+
* Uses base class UTXO selection logic with dashcore-lib transaction building.
|
|
87
|
+
*/
|
|
88
|
+
prepareTxEnhanced({ sender, memo, amount, recipient, feeRate, spendPendingUTXO, utxoSelectionPreferences, }: TxParams & {
|
|
89
|
+
sender: Address;
|
|
90
|
+
feeRate: FeeRate;
|
|
91
|
+
spendPendingUTXO?: boolean;
|
|
92
|
+
utxoSelectionPreferences?: UtxoSelectionPreferences;
|
|
93
|
+
}): Promise<PreparedTx>;
|
|
94
|
+
/**
|
|
95
|
+
* Prepare max send transaction
|
|
96
|
+
*/
|
|
97
|
+
prepareMaxTx({ sender, recipient, memo, feeRate, spendPendingUTXO, utxoSelectionPreferences, }: {
|
|
98
|
+
sender: Address;
|
|
99
|
+
recipient: Address;
|
|
100
|
+
memo?: string;
|
|
101
|
+
feeRate: FeeRate;
|
|
102
|
+
spendPendingUTXO?: boolean;
|
|
103
|
+
utxoSelectionPreferences?: UtxoSelectionPreferences;
|
|
104
|
+
}): Promise<PreparedTx & {
|
|
105
|
+
maxAmount: number;
|
|
106
|
+
fee: number;
|
|
107
|
+
}>;
|
|
83
108
|
}
|
|
84
109
|
export { Client };
|
package/lib/clientKeystore.d.ts
CHANGED
|
@@ -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 { ECPairInterface } from 'ecpair';
|
|
5
5
|
import { Client } from './client';
|
|
6
6
|
export declare class ClientKeystore extends Client {
|
|
@@ -30,10 +30,34 @@ export declare class ClientKeystore extends Client {
|
|
|
30
30
|
getDashKeys(phrase: string, index?: number): ECPairInterface;
|
|
31
31
|
/**
|
|
32
32
|
* Asynchronously transfers assets between addresses.
|
|
33
|
-
* @param {TxParams & { feeRate?: FeeRate }} params - Parameters for the transfer.
|
|
33
|
+
* @param {TxParams & { feeRate?: FeeRate; utxoSelectionPreferences?: UtxoSelectionPreferences }} params - Parameters for the transfer.
|
|
34
34
|
* @returns {Promise<TxHash>} A promise resolving to the transaction hash.
|
|
35
35
|
*/
|
|
36
36
|
transfer(params: TxParams & {
|
|
37
37
|
feeRate?: FeeRate;
|
|
38
|
+
utxoSelectionPreferences?: UtxoSelectionPreferences;
|
|
38
39
|
}): Promise<TxHash>;
|
|
40
|
+
/**
|
|
41
|
+
* Transfer the maximum amount of DASH (sweep).
|
|
42
|
+
*
|
|
43
|
+
* Calculates the maximum sendable amount after fees, signs, and broadcasts the transaction.
|
|
44
|
+
* @param {Object} params The transfer parameters.
|
|
45
|
+
* @param {string} params.recipient The recipient address.
|
|
46
|
+
* @param {string} [params.memo] Optional memo for the transaction.
|
|
47
|
+
* @param {FeeRate} [params.feeRate] Optional fee rate. Defaults to 'average' rate.
|
|
48
|
+
* @param {number} [params.walletIndex] Optional wallet index. Defaults to 0.
|
|
49
|
+
* @param {UtxoSelectionPreferences} [params.utxoSelectionPreferences] Optional UTXO selection preferences.
|
|
50
|
+
* @returns {Promise<{ hash: TxHash; maxAmount: number; fee: number }>} The transaction hash, amount sent, and fee.
|
|
51
|
+
*/
|
|
52
|
+
transferMax(params: {
|
|
53
|
+
recipient: Address;
|
|
54
|
+
memo?: string;
|
|
55
|
+
feeRate?: FeeRate;
|
|
56
|
+
walletIndex?: number;
|
|
57
|
+
utxoSelectionPreferences?: UtxoSelectionPreferences;
|
|
58
|
+
}): Promise<{
|
|
59
|
+
hash: TxHash;
|
|
60
|
+
maxAmount: number;
|
|
61
|
+
fee: number;
|
|
62
|
+
}>;
|
|
39
63
|
}
|
package/lib/index.esm.js
CHANGED
|
@@ -2,7 +2,7 @@ import { ExplorerProvider, Network, TxType, FeeOption, checkFeeBounds } from '@x
|
|
|
2
2
|
import { AssetType, baseAmount, assetToBase, assetAmount } from '@xchainjs/xchain-util';
|
|
3
3
|
import { BlockcypherProvider, BlockcypherNetwork, BitgoProvider } from '@xchainjs/xchain-utxo-providers';
|
|
4
4
|
import dashcore from '@dashevo/dashcore-lib';
|
|
5
|
-
import { toBitcoinJS, Client as Client$1 } from '@xchainjs/xchain-utxo';
|
|
5
|
+
import { toBitcoinJS, Client as Client$1, UtxoError } from '@xchainjs/xchain-utxo';
|
|
6
6
|
import * as Dash from 'bitcoinjs-lib';
|
|
7
7
|
import accumulative from 'coinselect/accumulative.js';
|
|
8
8
|
import * as ecc from '@bitcoin-js/tiny-secp256k1-asmjs';
|
|
@@ -4449,6 +4449,7 @@ class Client extends Client$1 {
|
|
|
4449
4449
|
}
|
|
4450
4450
|
/**
|
|
4451
4451
|
* Asynchronously prepares a transaction for sending assets.
|
|
4452
|
+
* @deprecated Use `prepareTxEnhanced` instead for better UTXO selection and error handling.
|
|
4452
4453
|
* @param {TxParams&Address&FeeRate} params - Parameters for the transaction preparation.
|
|
4453
4454
|
* @returns {string} A promise resolving to the prepared transaction data.
|
|
4454
4455
|
*/
|
|
@@ -4515,6 +4516,123 @@ class Client extends Client$1 {
|
|
|
4515
4516
|
// Ensure fee meets minimum requirement
|
|
4516
4517
|
return fee > TX_MIN_FEE ? fee : TX_MIN_FEE;
|
|
4517
4518
|
}
|
|
4519
|
+
// ==================== Enhanced Transaction Methods ====================
|
|
4520
|
+
/**
|
|
4521
|
+
* Prepare transaction with enhanced UTXO selection.
|
|
4522
|
+
* Uses base class UTXO selection logic with dashcore-lib transaction building.
|
|
4523
|
+
*/
|
|
4524
|
+
prepareTxEnhanced(_a) {
|
|
4525
|
+
return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
|
|
4526
|
+
try {
|
|
4527
|
+
// Validate inputs using base class method
|
|
4528
|
+
this.validateTransactionInputs({
|
|
4529
|
+
amount,
|
|
4530
|
+
recipient,
|
|
4531
|
+
memo,
|
|
4532
|
+
sender,
|
|
4533
|
+
feeRate,
|
|
4534
|
+
});
|
|
4535
|
+
// Get validated UTXOs using base class method
|
|
4536
|
+
const confirmedOnly = !spendPendingUTXO;
|
|
4537
|
+
const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
|
|
4538
|
+
const compiledMemo = memo ? this.compileMemo(memo) : null;
|
|
4539
|
+
const targetValue = amount.amount().toNumber();
|
|
4540
|
+
const extraOutputs = 1 + (compiledMemo ? 1 : 0);
|
|
4541
|
+
// Use base class UTXO selection
|
|
4542
|
+
const selectionResult = this.selectUtxosForTransaction(utxos, targetValue, Math.ceil(feeRate), extraOutputs, utxoSelectionPreferences);
|
|
4543
|
+
// Build transaction using dashcore-lib
|
|
4544
|
+
const tx = new dashcore.Transaction().to(recipient, targetValue);
|
|
4545
|
+
// Add selected inputs
|
|
4546
|
+
for (const utxo of selectionResult.inputs) {
|
|
4547
|
+
const scriptBuffer = Buffer.from(utxo.scriptPubKey || '', 'hex');
|
|
4548
|
+
const script = new dashcore.Script(scriptBuffer);
|
|
4549
|
+
const input = new dashcore.Transaction.Input.PublicKeyHash({
|
|
4550
|
+
prevTxId: Buffer.from(utxo.hash, 'hex'),
|
|
4551
|
+
outputIndex: utxo.index,
|
|
4552
|
+
script: '',
|
|
4553
|
+
output: new dashcore.Transaction.Output({
|
|
4554
|
+
satoshis: utxo.value,
|
|
4555
|
+
script,
|
|
4556
|
+
}),
|
|
4557
|
+
});
|
|
4558
|
+
tx.uncheckedAddInput(input);
|
|
4559
|
+
}
|
|
4560
|
+
// Set change address
|
|
4561
|
+
const senderAddress = dashcore.Address.fromString(sender, this.network);
|
|
4562
|
+
tx.change(senderAddress);
|
|
4563
|
+
// Add memo if provided
|
|
4564
|
+
if (memo) {
|
|
4565
|
+
tx.addData(memo);
|
|
4566
|
+
}
|
|
4567
|
+
// ESLint disabled: Dash transaction has proper toString() method that returns hex string
|
|
4568
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
4569
|
+
return { rawUnsignedTx: tx.toString(), utxos, inputs: selectionResult.inputs };
|
|
4570
|
+
}
|
|
4571
|
+
catch (error) {
|
|
4572
|
+
if (UtxoError.isUtxoError(error)) {
|
|
4573
|
+
throw error;
|
|
4574
|
+
}
|
|
4575
|
+
throw UtxoError.fromUnknown(error, 'prepareTxEnhanced');
|
|
4576
|
+
}
|
|
4577
|
+
});
|
|
4578
|
+
}
|
|
4579
|
+
/**
|
|
4580
|
+
* Prepare max send transaction
|
|
4581
|
+
*/
|
|
4582
|
+
prepareMaxTx(_a) {
|
|
4583
|
+
return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
|
|
4584
|
+
try {
|
|
4585
|
+
// Validate addresses
|
|
4586
|
+
if (!this.validateAddress(recipient)) {
|
|
4587
|
+
throw UtxoError.invalidAddress(recipient, this.network);
|
|
4588
|
+
}
|
|
4589
|
+
if (!this.validateAddress(sender)) {
|
|
4590
|
+
throw UtxoError.invalidAddress(sender, this.network);
|
|
4591
|
+
}
|
|
4592
|
+
// Get validated UTXOs
|
|
4593
|
+
const confirmedOnly = !spendPendingUTXO;
|
|
4594
|
+
const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
|
|
4595
|
+
// Calculate max using base class method
|
|
4596
|
+
const maxCalc = this.calculateMaxSendableAmount(utxos, Math.ceil(feeRate), !!memo, utxoSelectionPreferences);
|
|
4597
|
+
// Build transaction using dashcore-lib
|
|
4598
|
+
const tx = new dashcore.Transaction().to(recipient, maxCalc.amount);
|
|
4599
|
+
// Add inputs
|
|
4600
|
+
for (const utxo of maxCalc.inputs) {
|
|
4601
|
+
const scriptBuffer = Buffer.from(utxo.scriptPubKey || '', 'hex');
|
|
4602
|
+
const script = new dashcore.Script(scriptBuffer);
|
|
4603
|
+
const input = new dashcore.Transaction.Input.PublicKeyHash({
|
|
4604
|
+
prevTxId: Buffer.from(utxo.hash, 'hex'),
|
|
4605
|
+
outputIndex: utxo.index,
|
|
4606
|
+
script: '',
|
|
4607
|
+
output: new dashcore.Transaction.Output({
|
|
4608
|
+
satoshis: utxo.value,
|
|
4609
|
+
script,
|
|
4610
|
+
}),
|
|
4611
|
+
});
|
|
4612
|
+
tx.uncheckedAddInput(input);
|
|
4613
|
+
}
|
|
4614
|
+
// Add memo if provided
|
|
4615
|
+
if (memo) {
|
|
4616
|
+
tx.addData(memo);
|
|
4617
|
+
}
|
|
4618
|
+
// ESLint disabled: Dash transaction has proper toString() method that returns hex string
|
|
4619
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
4620
|
+
return {
|
|
4621
|
+
rawUnsignedTx: tx.toString(),
|
|
4622
|
+
utxos,
|
|
4623
|
+
inputs: maxCalc.inputs,
|
|
4624
|
+
maxAmount: maxCalc.amount,
|
|
4625
|
+
fee: maxCalc.fee,
|
|
4626
|
+
};
|
|
4627
|
+
}
|
|
4628
|
+
catch (error) {
|
|
4629
|
+
if (UtxoError.isUtxoError(error)) {
|
|
4630
|
+
throw error;
|
|
4631
|
+
}
|
|
4632
|
+
throw UtxoError.fromUnknown(error, 'prepareMaxTx');
|
|
4633
|
+
}
|
|
4634
|
+
});
|
|
4635
|
+
}
|
|
4518
4636
|
}
|
|
4519
4637
|
|
|
4520
4638
|
/**
|
|
@@ -4605,7 +4723,7 @@ class ClientKeystore extends Client {
|
|
|
4605
4723
|
}
|
|
4606
4724
|
/**
|
|
4607
4725
|
* Asynchronously transfers assets between addresses.
|
|
4608
|
-
* @param {TxParams & { feeRate?: FeeRate }} params - Parameters for the transfer.
|
|
4726
|
+
* @param {TxParams & { feeRate?: FeeRate; utxoSelectionPreferences?: UtxoSelectionPreferences }} params - Parameters for the transfer.
|
|
4609
4727
|
* @returns {Promise<TxHash>} A promise resolving to the transaction hash.
|
|
4610
4728
|
*/
|
|
4611
4729
|
transfer(params) {
|
|
@@ -4614,7 +4732,9 @@ class ClientKeystore extends Client {
|
|
|
4614
4732
|
const feeRate = params.feeRate || (yield this.getFeeRates())[FeeOption.Average];
|
|
4615
4733
|
checkFeeBounds(this.feeBounds, feeRate);
|
|
4616
4734
|
const fromAddressIndex = params.walletIndex || 0;
|
|
4617
|
-
|
|
4735
|
+
// Merge default preferences
|
|
4736
|
+
const mergedPreferences = Object.assign({ minimizeFee: true, avoidDust: true, minimizeInputs: false }, params.utxoSelectionPreferences);
|
|
4737
|
+
const { rawUnsignedTx, utxos } = yield this.prepareTxEnhanced(Object.assign(Object.assign({}, params), { feeRate, sender: yield this.getAddressAsync(fromAddressIndex), utxoSelectionPreferences: mergedPreferences }));
|
|
4618
4738
|
const tx = new dashcore.Transaction(rawUnsignedTx);
|
|
4619
4739
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4620
4740
|
tx.inputs.forEach((input, index) => {
|
|
@@ -4646,6 +4766,64 @@ class ClientKeystore extends Client {
|
|
|
4646
4766
|
});
|
|
4647
4767
|
});
|
|
4648
4768
|
}
|
|
4769
|
+
/**
|
|
4770
|
+
* Transfer the maximum amount of DASH (sweep).
|
|
4771
|
+
*
|
|
4772
|
+
* Calculates the maximum sendable amount after fees, signs, and broadcasts the transaction.
|
|
4773
|
+
* @param {Object} params The transfer parameters.
|
|
4774
|
+
* @param {string} params.recipient The recipient address.
|
|
4775
|
+
* @param {string} [params.memo] Optional memo for the transaction.
|
|
4776
|
+
* @param {FeeRate} [params.feeRate] Optional fee rate. Defaults to 'average' rate.
|
|
4777
|
+
* @param {number} [params.walletIndex] Optional wallet index. Defaults to 0.
|
|
4778
|
+
* @param {UtxoSelectionPreferences} [params.utxoSelectionPreferences] Optional UTXO selection preferences.
|
|
4779
|
+
* @returns {Promise<{ hash: TxHash; maxAmount: number; fee: number }>} The transaction hash, amount sent, and fee.
|
|
4780
|
+
*/
|
|
4781
|
+
transferMax(params) {
|
|
4782
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
4783
|
+
var _a;
|
|
4784
|
+
const feeRate = params.feeRate || (yield this.getFeeRates())[FeeOption.Average];
|
|
4785
|
+
checkFeeBounds(this.feeBounds, feeRate);
|
|
4786
|
+
const fromAddressIndex = params.walletIndex || 0;
|
|
4787
|
+
const sender = yield this.getAddressAsync(fromAddressIndex);
|
|
4788
|
+
const { rawUnsignedTx, utxos, maxAmount, fee } = yield this.prepareMaxTx({
|
|
4789
|
+
sender,
|
|
4790
|
+
recipient: params.recipient,
|
|
4791
|
+
memo: params.memo,
|
|
4792
|
+
feeRate,
|
|
4793
|
+
utxoSelectionPreferences: params.utxoSelectionPreferences,
|
|
4794
|
+
});
|
|
4795
|
+
const tx = new dashcore.Transaction(rawUnsignedTx);
|
|
4796
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4797
|
+
tx.inputs.forEach((input, index) => {
|
|
4798
|
+
const insightUtxo = utxos.find((utxo) => {
|
|
4799
|
+
return utxo.hash === input.prevTxId.toString('hex') && utxo.index == input.outputIndex;
|
|
4800
|
+
});
|
|
4801
|
+
if (!insightUtxo) {
|
|
4802
|
+
throw new Error('Unable to match accumulative inputs with insight utxos');
|
|
4803
|
+
}
|
|
4804
|
+
const scriptBuffer = Buffer.from(insightUtxo.scriptPubKey || '', 'hex');
|
|
4805
|
+
const script = new dashcore.Script(scriptBuffer);
|
|
4806
|
+
tx.inputs[index] = new dashcore.Transaction.Input.PublicKeyHash({
|
|
4807
|
+
prevTxId: Buffer.from(insightUtxo.hash, 'hex'),
|
|
4808
|
+
outputIndex: insightUtxo.index,
|
|
4809
|
+
script: '',
|
|
4810
|
+
output: new dashcore.Transaction.Output({
|
|
4811
|
+
satoshis: insightUtxo.value,
|
|
4812
|
+
script,
|
|
4813
|
+
}),
|
|
4814
|
+
});
|
|
4815
|
+
});
|
|
4816
|
+
const dashKeys = this.getDashKeys(this.phrase, fromAddressIndex);
|
|
4817
|
+
tx.sign(`${(_a = dashKeys.privateKey) === null || _a === void 0 ? void 0 : _a.toString('hex')}`);
|
|
4818
|
+
const txHex = tx.checkedSerialize({});
|
|
4819
|
+
const hash = yield broadcastTx({
|
|
4820
|
+
txHex,
|
|
4821
|
+
nodeUrl: this.nodeUrls[this.network],
|
|
4822
|
+
auth: this.nodeAuth,
|
|
4823
|
+
});
|
|
4824
|
+
return { hash, maxAmount, fee };
|
|
4825
|
+
});
|
|
4826
|
+
}
|
|
4649
4827
|
}
|
|
4650
4828
|
|
|
4651
4829
|
/**
|
package/lib/index.js
CHANGED
|
@@ -4477,6 +4477,7 @@ class Client extends xchainUtxo.Client {
|
|
|
4477
4477
|
}
|
|
4478
4478
|
/**
|
|
4479
4479
|
* Asynchronously prepares a transaction for sending assets.
|
|
4480
|
+
* @deprecated Use `prepareTxEnhanced` instead for better UTXO selection and error handling.
|
|
4480
4481
|
* @param {TxParams&Address&FeeRate} params - Parameters for the transaction preparation.
|
|
4481
4482
|
* @returns {string} A promise resolving to the prepared transaction data.
|
|
4482
4483
|
*/
|
|
@@ -4543,6 +4544,123 @@ class Client extends xchainUtxo.Client {
|
|
|
4543
4544
|
// Ensure fee meets minimum requirement
|
|
4544
4545
|
return fee > TX_MIN_FEE ? fee : TX_MIN_FEE;
|
|
4545
4546
|
}
|
|
4547
|
+
// ==================== Enhanced Transaction Methods ====================
|
|
4548
|
+
/**
|
|
4549
|
+
* Prepare transaction with enhanced UTXO selection.
|
|
4550
|
+
* Uses base class UTXO selection logic with dashcore-lib transaction building.
|
|
4551
|
+
*/
|
|
4552
|
+
prepareTxEnhanced(_a) {
|
|
4553
|
+
return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
|
|
4554
|
+
try {
|
|
4555
|
+
// Validate inputs using base class method
|
|
4556
|
+
this.validateTransactionInputs({
|
|
4557
|
+
amount,
|
|
4558
|
+
recipient,
|
|
4559
|
+
memo,
|
|
4560
|
+
sender,
|
|
4561
|
+
feeRate,
|
|
4562
|
+
});
|
|
4563
|
+
// Get validated UTXOs using base class method
|
|
4564
|
+
const confirmedOnly = !spendPendingUTXO;
|
|
4565
|
+
const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
|
|
4566
|
+
const compiledMemo = memo ? this.compileMemo(memo) : null;
|
|
4567
|
+
const targetValue = amount.amount().toNumber();
|
|
4568
|
+
const extraOutputs = 1 + (compiledMemo ? 1 : 0);
|
|
4569
|
+
// Use base class UTXO selection
|
|
4570
|
+
const selectionResult = this.selectUtxosForTransaction(utxos, targetValue, Math.ceil(feeRate), extraOutputs, utxoSelectionPreferences);
|
|
4571
|
+
// Build transaction using dashcore-lib
|
|
4572
|
+
const tx = new dashcore__default.default.Transaction().to(recipient, targetValue);
|
|
4573
|
+
// Add selected inputs
|
|
4574
|
+
for (const utxo of selectionResult.inputs) {
|
|
4575
|
+
const scriptBuffer = Buffer.from(utxo.scriptPubKey || '', 'hex');
|
|
4576
|
+
const script = new dashcore__default.default.Script(scriptBuffer);
|
|
4577
|
+
const input = new dashcore__default.default.Transaction.Input.PublicKeyHash({
|
|
4578
|
+
prevTxId: Buffer.from(utxo.hash, 'hex'),
|
|
4579
|
+
outputIndex: utxo.index,
|
|
4580
|
+
script: '',
|
|
4581
|
+
output: new dashcore__default.default.Transaction.Output({
|
|
4582
|
+
satoshis: utxo.value,
|
|
4583
|
+
script,
|
|
4584
|
+
}),
|
|
4585
|
+
});
|
|
4586
|
+
tx.uncheckedAddInput(input);
|
|
4587
|
+
}
|
|
4588
|
+
// Set change address
|
|
4589
|
+
const senderAddress = dashcore__default.default.Address.fromString(sender, this.network);
|
|
4590
|
+
tx.change(senderAddress);
|
|
4591
|
+
// Add memo if provided
|
|
4592
|
+
if (memo) {
|
|
4593
|
+
tx.addData(memo);
|
|
4594
|
+
}
|
|
4595
|
+
// ESLint disabled: Dash transaction has proper toString() method that returns hex string
|
|
4596
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
4597
|
+
return { rawUnsignedTx: tx.toString(), utxos, inputs: selectionResult.inputs };
|
|
4598
|
+
}
|
|
4599
|
+
catch (error) {
|
|
4600
|
+
if (xchainUtxo.UtxoError.isUtxoError(error)) {
|
|
4601
|
+
throw error;
|
|
4602
|
+
}
|
|
4603
|
+
throw xchainUtxo.UtxoError.fromUnknown(error, 'prepareTxEnhanced');
|
|
4604
|
+
}
|
|
4605
|
+
});
|
|
4606
|
+
}
|
|
4607
|
+
/**
|
|
4608
|
+
* Prepare max send transaction
|
|
4609
|
+
*/
|
|
4610
|
+
prepareMaxTx(_a) {
|
|
4611
|
+
return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
|
|
4612
|
+
try {
|
|
4613
|
+
// Validate addresses
|
|
4614
|
+
if (!this.validateAddress(recipient)) {
|
|
4615
|
+
throw xchainUtxo.UtxoError.invalidAddress(recipient, this.network);
|
|
4616
|
+
}
|
|
4617
|
+
if (!this.validateAddress(sender)) {
|
|
4618
|
+
throw xchainUtxo.UtxoError.invalidAddress(sender, this.network);
|
|
4619
|
+
}
|
|
4620
|
+
// Get validated UTXOs
|
|
4621
|
+
const confirmedOnly = !spendPendingUTXO;
|
|
4622
|
+
const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
|
|
4623
|
+
// Calculate max using base class method
|
|
4624
|
+
const maxCalc = this.calculateMaxSendableAmount(utxos, Math.ceil(feeRate), !!memo, utxoSelectionPreferences);
|
|
4625
|
+
// Build transaction using dashcore-lib
|
|
4626
|
+
const tx = new dashcore__default.default.Transaction().to(recipient, maxCalc.amount);
|
|
4627
|
+
// Add inputs
|
|
4628
|
+
for (const utxo of maxCalc.inputs) {
|
|
4629
|
+
const scriptBuffer = Buffer.from(utxo.scriptPubKey || '', 'hex');
|
|
4630
|
+
const script = new dashcore__default.default.Script(scriptBuffer);
|
|
4631
|
+
const input = new dashcore__default.default.Transaction.Input.PublicKeyHash({
|
|
4632
|
+
prevTxId: Buffer.from(utxo.hash, 'hex'),
|
|
4633
|
+
outputIndex: utxo.index,
|
|
4634
|
+
script: '',
|
|
4635
|
+
output: new dashcore__default.default.Transaction.Output({
|
|
4636
|
+
satoshis: utxo.value,
|
|
4637
|
+
script,
|
|
4638
|
+
}),
|
|
4639
|
+
});
|
|
4640
|
+
tx.uncheckedAddInput(input);
|
|
4641
|
+
}
|
|
4642
|
+
// Add memo if provided
|
|
4643
|
+
if (memo) {
|
|
4644
|
+
tx.addData(memo);
|
|
4645
|
+
}
|
|
4646
|
+
// ESLint disabled: Dash transaction has proper toString() method that returns hex string
|
|
4647
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
4648
|
+
return {
|
|
4649
|
+
rawUnsignedTx: tx.toString(),
|
|
4650
|
+
utxos,
|
|
4651
|
+
inputs: maxCalc.inputs,
|
|
4652
|
+
maxAmount: maxCalc.amount,
|
|
4653
|
+
fee: maxCalc.fee,
|
|
4654
|
+
};
|
|
4655
|
+
}
|
|
4656
|
+
catch (error) {
|
|
4657
|
+
if (xchainUtxo.UtxoError.isUtxoError(error)) {
|
|
4658
|
+
throw error;
|
|
4659
|
+
}
|
|
4660
|
+
throw xchainUtxo.UtxoError.fromUnknown(error, 'prepareMaxTx');
|
|
4661
|
+
}
|
|
4662
|
+
});
|
|
4663
|
+
}
|
|
4546
4664
|
}
|
|
4547
4665
|
|
|
4548
4666
|
/**
|
|
@@ -4633,7 +4751,7 @@ class ClientKeystore extends Client {
|
|
|
4633
4751
|
}
|
|
4634
4752
|
/**
|
|
4635
4753
|
* Asynchronously transfers assets between addresses.
|
|
4636
|
-
* @param {TxParams & { feeRate?: FeeRate }} params - Parameters for the transfer.
|
|
4754
|
+
* @param {TxParams & { feeRate?: FeeRate; utxoSelectionPreferences?: UtxoSelectionPreferences }} params - Parameters for the transfer.
|
|
4637
4755
|
* @returns {Promise<TxHash>} A promise resolving to the transaction hash.
|
|
4638
4756
|
*/
|
|
4639
4757
|
transfer(params) {
|
|
@@ -4642,7 +4760,9 @@ class ClientKeystore extends Client {
|
|
|
4642
4760
|
const feeRate = params.feeRate || (yield this.getFeeRates())[xchainClient.FeeOption.Average];
|
|
4643
4761
|
xchainClient.checkFeeBounds(this.feeBounds, feeRate);
|
|
4644
4762
|
const fromAddressIndex = params.walletIndex || 0;
|
|
4645
|
-
|
|
4763
|
+
// Merge default preferences
|
|
4764
|
+
const mergedPreferences = Object.assign({ minimizeFee: true, avoidDust: true, minimizeInputs: false }, params.utxoSelectionPreferences);
|
|
4765
|
+
const { rawUnsignedTx, utxos } = yield this.prepareTxEnhanced(Object.assign(Object.assign({}, params), { feeRate, sender: yield this.getAddressAsync(fromAddressIndex), utxoSelectionPreferences: mergedPreferences }));
|
|
4646
4766
|
const tx = new dashcore__default.default.Transaction(rawUnsignedTx);
|
|
4647
4767
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4648
4768
|
tx.inputs.forEach((input, index) => {
|
|
@@ -4674,6 +4794,64 @@ class ClientKeystore extends Client {
|
|
|
4674
4794
|
});
|
|
4675
4795
|
});
|
|
4676
4796
|
}
|
|
4797
|
+
/**
|
|
4798
|
+
* Transfer the maximum amount of DASH (sweep).
|
|
4799
|
+
*
|
|
4800
|
+
* Calculates the maximum sendable amount after fees, signs, and broadcasts the transaction.
|
|
4801
|
+
* @param {Object} params The transfer parameters.
|
|
4802
|
+
* @param {string} params.recipient The recipient address.
|
|
4803
|
+
* @param {string} [params.memo] Optional memo for the transaction.
|
|
4804
|
+
* @param {FeeRate} [params.feeRate] Optional fee rate. Defaults to 'average' rate.
|
|
4805
|
+
* @param {number} [params.walletIndex] Optional wallet index. Defaults to 0.
|
|
4806
|
+
* @param {UtxoSelectionPreferences} [params.utxoSelectionPreferences] Optional UTXO selection preferences.
|
|
4807
|
+
* @returns {Promise<{ hash: TxHash; maxAmount: number; fee: number }>} The transaction hash, amount sent, and fee.
|
|
4808
|
+
*/
|
|
4809
|
+
transferMax(params) {
|
|
4810
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
4811
|
+
var _a;
|
|
4812
|
+
const feeRate = params.feeRate || (yield this.getFeeRates())[xchainClient.FeeOption.Average];
|
|
4813
|
+
xchainClient.checkFeeBounds(this.feeBounds, feeRate);
|
|
4814
|
+
const fromAddressIndex = params.walletIndex || 0;
|
|
4815
|
+
const sender = yield this.getAddressAsync(fromAddressIndex);
|
|
4816
|
+
const { rawUnsignedTx, utxos, maxAmount, fee } = yield this.prepareMaxTx({
|
|
4817
|
+
sender,
|
|
4818
|
+
recipient: params.recipient,
|
|
4819
|
+
memo: params.memo,
|
|
4820
|
+
feeRate,
|
|
4821
|
+
utxoSelectionPreferences: params.utxoSelectionPreferences,
|
|
4822
|
+
});
|
|
4823
|
+
const tx = new dashcore__default.default.Transaction(rawUnsignedTx);
|
|
4824
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4825
|
+
tx.inputs.forEach((input, index) => {
|
|
4826
|
+
const insightUtxo = utxos.find((utxo) => {
|
|
4827
|
+
return utxo.hash === input.prevTxId.toString('hex') && utxo.index == input.outputIndex;
|
|
4828
|
+
});
|
|
4829
|
+
if (!insightUtxo) {
|
|
4830
|
+
throw new Error('Unable to match accumulative inputs with insight utxos');
|
|
4831
|
+
}
|
|
4832
|
+
const scriptBuffer = Buffer.from(insightUtxo.scriptPubKey || '', 'hex');
|
|
4833
|
+
const script = new dashcore__default.default.Script(scriptBuffer);
|
|
4834
|
+
tx.inputs[index] = new dashcore__default.default.Transaction.Input.PublicKeyHash({
|
|
4835
|
+
prevTxId: Buffer.from(insightUtxo.hash, 'hex'),
|
|
4836
|
+
outputIndex: insightUtxo.index,
|
|
4837
|
+
script: '',
|
|
4838
|
+
output: new dashcore__default.default.Transaction.Output({
|
|
4839
|
+
satoshis: insightUtxo.value,
|
|
4840
|
+
script,
|
|
4841
|
+
}),
|
|
4842
|
+
});
|
|
4843
|
+
});
|
|
4844
|
+
const dashKeys = this.getDashKeys(this.phrase, fromAddressIndex);
|
|
4845
|
+
tx.sign(`${(_a = dashKeys.privateKey) === null || _a === void 0 ? void 0 : _a.toString('hex')}`);
|
|
4846
|
+
const txHex = tx.checkedSerialize({});
|
|
4847
|
+
const hash = yield broadcastTx({
|
|
4848
|
+
txHex,
|
|
4849
|
+
nodeUrl: this.nodeUrls[this.network],
|
|
4850
|
+
auth: this.nodeAuth,
|
|
4851
|
+
});
|
|
4852
|
+
return { hash, maxAmount, fee };
|
|
4853
|
+
});
|
|
4854
|
+
}
|
|
4677
4855
|
}
|
|
4678
4856
|
|
|
4679
4857
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xchainjs/xchain-dash",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Custom Dash client and utilities used by XChainJS clients",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"XChain",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@xchainjs/xchain-client": "2.0.10",
|
|
41
41
|
"@xchainjs/xchain-crypto": "1.0.6",
|
|
42
42
|
"@xchainjs/xchain-util": "2.0.5",
|
|
43
|
-
"@xchainjs/xchain-utxo": "2.0
|
|
43
|
+
"@xchainjs/xchain-utxo": "2.1.0",
|
|
44
44
|
"@xchainjs/xchain-utxo-providers": "2.0.10",
|
|
45
45
|
"bitcoinjs-lib": "^6.1.7",
|
|
46
46
|
"coinselect": "3.1.12",
|