@xchainjs/xchain-dash 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
@@ -85,22 +85,24 @@ declare abstract class Client extends UTXOClient {
85
85
  * Prepare transaction with enhanced UTXO selection.
86
86
  * Uses base class UTXO selection logic with dashcore-lib transaction building.
87
87
  */
88
- prepareTxEnhanced({ sender, memo, amount, recipient, feeRate, spendPendingUTXO, utxoSelectionPreferences, }: TxParams & {
88
+ prepareTxEnhanced({ sender, memo, amount, recipient, feeRate, spendPendingUTXO, utxoSelectionPreferences, selectedUtxos, }: TxParams & {
89
89
  sender: Address;
90
90
  feeRate: FeeRate;
91
91
  spendPendingUTXO?: boolean;
92
92
  utxoSelectionPreferences?: UtxoSelectionPreferences;
93
+ selectedUtxos?: UTXO[];
93
94
  }): Promise<PreparedTx>;
94
95
  /**
95
96
  * Prepare max send transaction
96
97
  */
97
- prepareMaxTx({ sender, recipient, memo, feeRate, spendPendingUTXO, utxoSelectionPreferences, }: {
98
+ prepareMaxTx({ sender, recipient, memo, feeRate, spendPendingUTXO, utxoSelectionPreferences, selectedUtxos, }: {
98
99
  sender: Address;
99
100
  recipient: Address;
100
101
  memo?: string;
101
102
  feeRate: FeeRate;
102
103
  spendPendingUTXO?: boolean;
103
104
  utxoSelectionPreferences?: UtxoSelectionPreferences;
105
+ selectedUtxos?: UTXO[];
104
106
  }): Promise<PreparedTx & {
105
107
  maxAmount: number;
106
108
  fee: number;
@@ -1,6 +1,6 @@
1
1
  import { FeeRate, TxHash } from '@xchainjs/xchain-client';
2
2
  import { Address } from '@xchainjs/xchain-util';
3
- import { TxParams, UtxoSelectionPreferences } from '@xchainjs/xchain-utxo';
3
+ import { TxParams, UTXO, 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 {
@@ -36,6 +36,7 @@ export declare class ClientKeystore extends Client {
36
36
  transfer(params: TxParams & {
37
37
  feeRate?: FeeRate;
38
38
  utxoSelectionPreferences?: UtxoSelectionPreferences;
39
+ selectedUtxos?: UTXO[];
39
40
  }): Promise<TxHash>;
40
41
  /**
41
42
  * Transfer the maximum amount of DASH (sweep).
@@ -55,6 +56,7 @@ export declare class ClientKeystore extends Client {
55
56
  feeRate?: FeeRate;
56
57
  walletIndex?: number;
57
58
  utxoSelectionPreferences?: UtxoSelectionPreferences;
59
+ selectedUtxos?: UTXO[];
58
60
  }): Promise<{
59
61
  hash: TxHash;
60
62
  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 } from '@xchainjs/xchain-utxo';
4
+ import { TxParams, UTXO, UtxoClientParams, UtxoSelectionPreferences } from '@xchainjs/xchain-utxo';
5
5
  import { Client } from './client';
6
6
  import { NodeAuth, NodeUrls } from './types';
7
7
  /**
@@ -21,5 +21,17 @@ declare class ClientLedger extends Client {
21
21
  transfer(params: TxParams & {
22
22
  feeRate?: FeeRate;
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
@@ -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, UtxoError } from '@xchainjs/xchain-utxo';
5
+ import { toBitcoinJS, Client as Client$1, UtxoTransactionValidator, 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';
@@ -4522,7 +4522,7 @@ class Client extends Client$1 {
4522
4522
  * Uses base class UTXO selection logic with dashcore-lib transaction building.
4523
4523
  */
4524
4524
  prepareTxEnhanced(_a) {
4525
- return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
4525
+ return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, selectedUtxos, }) {
4526
4526
  try {
4527
4527
  // Validate inputs using base class method
4528
4528
  this.validateTransactionInputs({
@@ -4532,9 +4532,16 @@ class Client extends Client$1 {
4532
4532
  sender,
4533
4533
  feeRate,
4534
4534
  });
4535
- // Get validated UTXOs using base class method
4536
- const confirmedOnly = !spendPendingUTXO;
4537
- const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
4535
+ // Use provided UTXOs (coin control) or fetch from chain
4536
+ let utxos;
4537
+ if (selectedUtxos && selectedUtxos.length > 0) {
4538
+ UtxoTransactionValidator.validateUtxoSet(selectedUtxos);
4539
+ utxos = selectedUtxos;
4540
+ }
4541
+ else {
4542
+ const confirmedOnly = !spendPendingUTXO;
4543
+ utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
4544
+ }
4538
4545
  const compiledMemo = memo ? this.compileMemo(memo) : null;
4539
4546
  const targetValue = amount.amount().toNumber();
4540
4547
  const extraOutputs = 1 + (compiledMemo ? 1 : 0);
@@ -4580,7 +4587,7 @@ class Client extends Client$1 {
4580
4587
  * Prepare max send transaction
4581
4588
  */
4582
4589
  prepareMaxTx(_a) {
4583
- return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
4590
+ return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, selectedUtxos, }) {
4584
4591
  try {
4585
4592
  // Validate addresses
4586
4593
  if (!this.validateAddress(recipient)) {
@@ -4589,9 +4596,16 @@ class Client extends Client$1 {
4589
4596
  if (!this.validateAddress(sender)) {
4590
4597
  throw UtxoError.invalidAddress(sender, this.network);
4591
4598
  }
4592
- // Get validated UTXOs
4593
- const confirmedOnly = !spendPendingUTXO;
4594
- const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
4599
+ // Use provided UTXOs (coin control) or fetch from chain
4600
+ let utxos;
4601
+ if (selectedUtxos && selectedUtxos.length > 0) {
4602
+ UtxoTransactionValidator.validateUtxoSet(selectedUtxos);
4603
+ utxos = selectedUtxos;
4604
+ }
4605
+ else {
4606
+ const confirmedOnly = !spendPendingUTXO;
4607
+ utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
4608
+ }
4595
4609
  // Calculate max using base class method
4596
4610
  const maxCalc = this.calculateMaxSendableAmount(utxos, Math.ceil(feeRate), !!memo, utxoSelectionPreferences);
4597
4611
  // Build transaction using dashcore-lib
@@ -4734,7 +4748,7 @@ class ClientKeystore extends Client {
4734
4748
  const fromAddressIndex = params.walletIndex || 0;
4735
4749
  // Merge default preferences
4736
4750
  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 }));
4751
+ const { rawUnsignedTx, utxos } = yield this.prepareTxEnhanced(Object.assign(Object.assign({}, params), { feeRate, sender: yield this.getAddressAsync(fromAddressIndex), utxoSelectionPreferences: mergedPreferences, selectedUtxos: params.selectedUtxos }));
4738
4752
  const tx = new dashcore.Transaction(rawUnsignedTx);
4739
4753
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
4740
4754
  tx.inputs.forEach((input, index) => {
@@ -4791,6 +4805,7 @@ class ClientKeystore extends Client {
4791
4805
  memo: params.memo,
4792
4806
  feeRate,
4793
4807
  utxoSelectionPreferences: params.utxoSelectionPreferences,
4808
+ selectedUtxos: params.selectedUtxos,
4794
4809
  });
4795
4810
  const tx = new dashcore.Transaction(rawUnsignedTx);
4796
4811
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -4916,6 +4931,58 @@ class ClientLedger extends Client {
4916
4931
  return txHash;
4917
4932
  });
4918
4933
  }
4934
+ // Transfer max DASH from Ledger (sweep transaction)
4935
+ transferMax(params) {
4936
+ return __awaiter(this, void 0, void 0, function* () {
4937
+ const app = yield this.getApp();
4938
+ const fromAddressIndex = (params === null || params === void 0 ? void 0 : params.walletIndex) || 0;
4939
+ const feeRate = params.feeRate || (yield this.getFeeRates())[FeeOption.Fast];
4940
+ checkFeeBounds(this.feeBounds, feeRate);
4941
+ const sender = yield this.getAddressAsync(fromAddressIndex);
4942
+ const { rawUnsignedTx, inputs, maxAmount, fee } = yield this.prepareMaxTx({
4943
+ sender,
4944
+ recipient: params.recipient,
4945
+ memo: params.memo,
4946
+ feeRate,
4947
+ utxoSelectionPreferences: params.utxoSelectionPreferences,
4948
+ selectedUtxos: params.selectedUtxos,
4949
+ });
4950
+ const tx = new dashcore.Transaction(rawUnsignedTx);
4951
+ const ledgerInputs = [];
4952
+ for (const input of tx.inputs) {
4953
+ const insightUtxo = inputs.find((utxo) => {
4954
+ return utxo.hash === input.prevTxId.toString('hex') && utxo.index == input.outputIndex;
4955
+ });
4956
+ if (!insightUtxo) {
4957
+ throw new Error('Unable to match accumulative inputs with insight utxos');
4958
+ }
4959
+ const txHex = yield getRawTx({ txid: insightUtxo.hash, network: this.network });
4960
+ const utxoTx = new dashcore.Transaction(txHex);
4961
+ const splittedTx = app.splitTransaction(utxoTx.toString());
4962
+ ledgerInputs.push([splittedTx, input.outputIndex, null, null]);
4963
+ }
4964
+ const associatedKeysets = tx.inputs.map(() => this.getFullDerivationPath(fromAddressIndex));
4965
+ const newTx = app.splitTransaction(tx.toString(), true);
4966
+ const outputScriptHex = app.serializeTransactionOutputs(newTx).toString('hex');
4967
+ const txHex = yield app.createPaymentTransaction({
4968
+ inputs: ledgerInputs,
4969
+ associatedKeysets,
4970
+ outputScriptHex,
4971
+ segwit: false,
4972
+ useTrustedInputForSegwit: false,
4973
+ additionals: [],
4974
+ });
4975
+ const hash = yield broadcastTx({
4976
+ txHex,
4977
+ nodeUrl: this.nodeUrls[this.network],
4978
+ auth: this.nodeAuth,
4979
+ });
4980
+ if (!hash) {
4981
+ throw Error('No Tx hash');
4982
+ }
4983
+ return { hash, maxAmount, fee };
4984
+ });
4985
+ }
4919
4986
  }
4920
4987
 
4921
4988
  export { AssetDASH, BitgoProviders, BlockcypherDataProviders, ClientKeystore as Client, ClientKeystore, ClientLedger, DASHChain, DASH_DECIMAL, DASH_SYMBOL, DEFAULT_FEE_RATE, LOWER_FEE_BOUND, MIN_TX_FEE, UPPER_FEE_BOUND, buildTx, defaultDashParams, explorerProviders, getPrefix, validateAddress };
package/lib/index.js CHANGED
@@ -4550,7 +4550,7 @@ class Client extends xchainUtxo.Client {
4550
4550
  * Uses base class UTXO selection logic with dashcore-lib transaction building.
4551
4551
  */
4552
4552
  prepareTxEnhanced(_a) {
4553
- return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
4553
+ return __awaiter(this, arguments, void 0, function* ({ sender, memo, amount, recipient, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, selectedUtxos, }) {
4554
4554
  try {
4555
4555
  // Validate inputs using base class method
4556
4556
  this.validateTransactionInputs({
@@ -4560,9 +4560,16 @@ class Client extends xchainUtxo.Client {
4560
4560
  sender,
4561
4561
  feeRate,
4562
4562
  });
4563
- // Get validated UTXOs using base class method
4564
- const confirmedOnly = !spendPendingUTXO;
4565
- const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
4563
+ // Use provided UTXOs (coin control) or fetch from chain
4564
+ let utxos;
4565
+ if (selectedUtxos && selectedUtxos.length > 0) {
4566
+ xchainUtxo.UtxoTransactionValidator.validateUtxoSet(selectedUtxos);
4567
+ utxos = selectedUtxos;
4568
+ }
4569
+ else {
4570
+ const confirmedOnly = !spendPendingUTXO;
4571
+ utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
4572
+ }
4566
4573
  const compiledMemo = memo ? this.compileMemo(memo) : null;
4567
4574
  const targetValue = amount.amount().toNumber();
4568
4575
  const extraOutputs = 1 + (compiledMemo ? 1 : 0);
@@ -4608,7 +4615,7 @@ class Client extends xchainUtxo.Client {
4608
4615
  * Prepare max send transaction
4609
4616
  */
4610
4617
  prepareMaxTx(_a) {
4611
- return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, }) {
4618
+ return __awaiter(this, arguments, void 0, function* ({ sender, recipient, memo, feeRate, spendPendingUTXO = true, utxoSelectionPreferences, selectedUtxos, }) {
4612
4619
  try {
4613
4620
  // Validate addresses
4614
4621
  if (!this.validateAddress(recipient)) {
@@ -4617,9 +4624,16 @@ class Client extends xchainUtxo.Client {
4617
4624
  if (!this.validateAddress(sender)) {
4618
4625
  throw xchainUtxo.UtxoError.invalidAddress(sender, this.network);
4619
4626
  }
4620
- // Get validated UTXOs
4621
- const confirmedOnly = !spendPendingUTXO;
4622
- const utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
4627
+ // Use provided UTXOs (coin control) or fetch from chain
4628
+ let utxos;
4629
+ if (selectedUtxos && selectedUtxos.length > 0) {
4630
+ xchainUtxo.UtxoTransactionValidator.validateUtxoSet(selectedUtxos);
4631
+ utxos = selectedUtxos;
4632
+ }
4633
+ else {
4634
+ const confirmedOnly = !spendPendingUTXO;
4635
+ utxos = yield this.getValidatedUtxos(sender, confirmedOnly);
4636
+ }
4623
4637
  // Calculate max using base class method
4624
4638
  const maxCalc = this.calculateMaxSendableAmount(utxos, Math.ceil(feeRate), !!memo, utxoSelectionPreferences);
4625
4639
  // Build transaction using dashcore-lib
@@ -4762,7 +4776,7 @@ class ClientKeystore extends Client {
4762
4776
  const fromAddressIndex = params.walletIndex || 0;
4763
4777
  // Merge default preferences
4764
4778
  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 }));
4779
+ const { rawUnsignedTx, utxos } = yield this.prepareTxEnhanced(Object.assign(Object.assign({}, params), { feeRate, sender: yield this.getAddressAsync(fromAddressIndex), utxoSelectionPreferences: mergedPreferences, selectedUtxos: params.selectedUtxos }));
4766
4780
  const tx = new dashcore__default.default.Transaction(rawUnsignedTx);
4767
4781
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
4768
4782
  tx.inputs.forEach((input, index) => {
@@ -4819,6 +4833,7 @@ class ClientKeystore extends Client {
4819
4833
  memo: params.memo,
4820
4834
  feeRate,
4821
4835
  utxoSelectionPreferences: params.utxoSelectionPreferences,
4836
+ selectedUtxos: params.selectedUtxos,
4822
4837
  });
4823
4838
  const tx = new dashcore__default.default.Transaction(rawUnsignedTx);
4824
4839
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -4944,6 +4959,58 @@ class ClientLedger extends Client {
4944
4959
  return txHash;
4945
4960
  });
4946
4961
  }
4962
+ // Transfer max DASH from Ledger (sweep transaction)
4963
+ transferMax(params) {
4964
+ return __awaiter(this, void 0, void 0, function* () {
4965
+ const app = yield this.getApp();
4966
+ const fromAddressIndex = (params === null || params === void 0 ? void 0 : params.walletIndex) || 0;
4967
+ const feeRate = params.feeRate || (yield this.getFeeRates())[xchainClient.FeeOption.Fast];
4968
+ xchainClient.checkFeeBounds(this.feeBounds, feeRate);
4969
+ const sender = yield this.getAddressAsync(fromAddressIndex);
4970
+ const { rawUnsignedTx, inputs, maxAmount, fee } = yield this.prepareMaxTx({
4971
+ sender,
4972
+ recipient: params.recipient,
4973
+ memo: params.memo,
4974
+ feeRate,
4975
+ utxoSelectionPreferences: params.utxoSelectionPreferences,
4976
+ selectedUtxos: params.selectedUtxos,
4977
+ });
4978
+ const tx = new dashcore__default.default.Transaction(rawUnsignedTx);
4979
+ const ledgerInputs = [];
4980
+ for (const input of tx.inputs) {
4981
+ const insightUtxo = inputs.find((utxo) => {
4982
+ return utxo.hash === input.prevTxId.toString('hex') && utxo.index == input.outputIndex;
4983
+ });
4984
+ if (!insightUtxo) {
4985
+ throw new Error('Unable to match accumulative inputs with insight utxos');
4986
+ }
4987
+ const txHex = yield getRawTx({ txid: insightUtxo.hash, network: this.network });
4988
+ const utxoTx = new dashcore__default.default.Transaction(txHex);
4989
+ const splittedTx = app.splitTransaction(utxoTx.toString());
4990
+ ledgerInputs.push([splittedTx, input.outputIndex, null, null]);
4991
+ }
4992
+ const associatedKeysets = tx.inputs.map(() => this.getFullDerivationPath(fromAddressIndex));
4993
+ const newTx = app.splitTransaction(tx.toString(), true);
4994
+ const outputScriptHex = app.serializeTransactionOutputs(newTx).toString('hex');
4995
+ const txHex = yield app.createPaymentTransaction({
4996
+ inputs: ledgerInputs,
4997
+ associatedKeysets,
4998
+ outputScriptHex,
4999
+ segwit: false,
5000
+ useTrustedInputForSegwit: false,
5001
+ additionals: [],
5002
+ });
5003
+ const hash = yield broadcastTx({
5004
+ txHex,
5005
+ nodeUrl: this.nodeUrls[this.network],
5006
+ auth: this.nodeAuth,
5007
+ });
5008
+ if (!hash) {
5009
+ throw Error('No Tx hash');
5010
+ }
5011
+ return { hash, maxAmount, fee };
5012
+ });
5013
+ }
4947
5014
  }
4948
5015
 
4949
5016
  exports.AssetDASH = AssetDASH;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xchainjs/xchain-dash",
3
- "version": "2.1.0",
3
+ "version": "2.2.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.1.0",
43
+ "@xchainjs/xchain-utxo": "2.2.0",
44
44
  "@xchainjs/xchain-utxo-providers": "2.0.10",
45
45
  "bitcoinjs-lib": "^6.1.7",
46
46
  "coinselect": "3.1.12",