@yaswap/yacoin 3.4.1 → 3.4.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @yaswap/bitcoin
2
2
 
3
+ ## 3.4.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Support HD wallet logic
8
+ - Updated dependencies
9
+ - @yaswap/client@3.4.2
10
+ - @yaswap/errors@3.4.2
11
+ - @yaswap/types@3.4.2
12
+ - @yaswap/utils@3.4.2
13
+
3
14
  ## 3.4.1
4
15
 
5
16
  ### Patch Changes
@@ -8,7 +8,7 @@ export { YacoinSwapBaseProvider } from './swap/YacoinSwapBaseProvider';
8
8
  export { YacoinSwapEsploraProvider } from './swap/YacoinSwapEsploraProvider';
9
9
  export * as YacoinTypes from './types';
10
10
  export * as YacoinUtils from './utils';
11
- export { YacoinBaseWalletProvider } from './wallet/YacoinBaseWallet';
11
+ export { AddressSearchType, YacoinBaseWalletProvider, NUMBER_ADDRESS_LIMIT } from './wallet/YacoinBaseWallet';
12
12
  export { YacoinHDWalletProvider } from './wallet/YacoinHDWallet';
13
13
  export { YacoinNftProvider } from './nft/YacoinNftProvider';
14
14
  export { YacoinSingleWallet } from './wallet/YacoinSingleWallet';
package/dist/lib/index.js CHANGED
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.YacoinSingleWallet = exports.YacoinNftProvider = exports.YacoinHDWalletProvider = exports.YacoinBaseWalletProvider = exports.YacoinUtils = exports.YacoinTypes = exports.YacoinSwapEsploraProvider = exports.YacoinSwapBaseProvider = exports.YacoinNetworks = exports.YacoinFeeApiProvider = exports.YacoinEsploraBatchBaseProvider = exports.YacoinEsploraBaseProvider = exports.YacoinEsploraApiProvider = exports.YacoinBaseChainProvider = void 0;
26
+ exports.YacoinSingleWallet = exports.YacoinNftProvider = exports.YacoinHDWalletProvider = exports.NUMBER_ADDRESS_LIMIT = exports.YacoinBaseWalletProvider = exports.AddressSearchType = exports.YacoinUtils = exports.YacoinTypes = exports.YacoinSwapEsploraProvider = exports.YacoinSwapBaseProvider = exports.YacoinNetworks = exports.YacoinFeeApiProvider = exports.YacoinEsploraBatchBaseProvider = exports.YacoinEsploraBaseProvider = exports.YacoinEsploraApiProvider = exports.YacoinBaseChainProvider = void 0;
27
27
  var YacoinBaseChainProvider_1 = require("./chain/YacoinBaseChainProvider");
28
28
  Object.defineProperty(exports, "YacoinBaseChainProvider", { enumerable: true, get: function () { return YacoinBaseChainProvider_1.YacoinBaseChainProvider; } });
29
29
  var YacoinEsploraApiProvider_1 = require("./chain/esplora/YacoinEsploraApiProvider");
@@ -43,7 +43,9 @@ Object.defineProperty(exports, "YacoinSwapEsploraProvider", { enumerable: true,
43
43
  exports.YacoinTypes = __importStar(require("./types"));
44
44
  exports.YacoinUtils = __importStar(require("./utils"));
45
45
  var YacoinBaseWallet_1 = require("./wallet/YacoinBaseWallet");
46
+ Object.defineProperty(exports, "AddressSearchType", { enumerable: true, get: function () { return YacoinBaseWallet_1.AddressSearchType; } });
46
47
  Object.defineProperty(exports, "YacoinBaseWalletProvider", { enumerable: true, get: function () { return YacoinBaseWallet_1.YacoinBaseWalletProvider; } });
48
+ Object.defineProperty(exports, "NUMBER_ADDRESS_LIMIT", { enumerable: true, get: function () { return YacoinBaseWallet_1.NUMBER_ADDRESS_LIMIT; } });
47
49
  var YacoinHDWallet_1 = require("./wallet/YacoinHDWallet");
48
50
  Object.defineProperty(exports, "YacoinHDWalletProvider", { enumerable: true, get: function () { return YacoinHDWallet_1.YacoinHDWalletProvider; } });
49
51
  var YacoinNftProvider_1 = require("./nft/YacoinNftProvider");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2EAA0E;AAAjE,kIAAA,uBAAuB,OAAA;AAChC,qFAAoF;AAA3E,oIAAA,wBAAwB,OAAA;AACjC,uFAAsF;AAA7E,sIAAA,yBAAyB,OAAA;AAClC,iGAAgG;AAAvF,gJAAA,8BAA8B,OAAA;AACvC,mEAAkE;AAAzD,4HAAA,oBAAoB,OAAA;AAC7B,uCAA4C;AAAnC,0GAAA,cAAc,OAAA;AACvB,wEAAuE;AAA9D,gIAAA,sBAAsB,OAAA;AAC/B,8EAA6E;AAApE,sIAAA,yBAAyB,OAAA;AAClC,uDAAuC;AACvC,uDAAuC;AACvC,8DAAqE;AAA5D,4HAAA,wBAAwB,OAAA;AACjC,0DAAiE;AAAxD,wHAAA,sBAAsB,OAAA;AAC/B,6DAA4D;AAAnD,sHAAA,iBAAiB,OAAA;AAC1B,kEAAiE;AAAxD,wHAAA,kBAAkB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2EAA0E;AAAjE,kIAAA,uBAAuB,OAAA;AAChC,qFAAoF;AAA3E,oIAAA,wBAAwB,OAAA;AACjC,uFAAsF;AAA7E,sIAAA,yBAAyB,OAAA;AAClC,iGAAgG;AAAvF,gJAAA,8BAA8B,OAAA;AACvC,mEAAkE;AAAzD,4HAAA,oBAAoB,OAAA;AAC7B,uCAA4C;AAAnC,0GAAA,cAAc,OAAA;AACvB,wEAAuE;AAA9D,gIAAA,sBAAsB,OAAA;AAC/B,8EAA6E;AAApE,sIAAA,yBAAyB,OAAA;AAClC,uDAAuC;AACvC,uDAAuC;AACvC,8DAA8G;AAArG,qHAAA,iBAAiB,OAAA;AAAE,4HAAA,wBAAwB,OAAA;AAAE,wHAAA,oBAAoB,OAAA;AAC1E,0DAAiE;AAAxD,wHAAA,sBAAsB,OAAA;AAC/B,6DAA4D;AAAnD,sHAAA,iBAAiB,OAAA;AAC1B,kEAAiE;AAAxD,wHAAA,kBAAkB,OAAA"}
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { Network, TokenScriptType } from '@yaswap/types';
2
+ import { Address, Network, TokenScriptType, TransactionRequest } from '@yaswap/types';
3
3
  import { ECPairInterface, Network as YacoinJsLibNetwork } from '@yaswap/yacoinjs-lib';
4
4
  export * as YacoinEsploraTypes from './chain/esplora/types';
5
5
  export * from './swap/types';
@@ -18,7 +18,17 @@ export interface YacoinWalletProviderOptions extends YacoinNodeWalletOptions {
18
18
  baseDerivationPath: string;
19
19
  }
20
20
  export interface YacoinHDWalletProviderOptions extends YacoinWalletProviderOptions {
21
- mnemonic: string;
21
+ mnemonic?: string;
22
+ extendedPublicKey?: RawExtendedPublicKey;
23
+ extendedPrivateKey?: RawExtendedPrivateKey;
24
+ }
25
+ export interface RawExtendedPublicKey {
26
+ publicKey: Buffer;
27
+ chainCode: Buffer;
28
+ }
29
+ export interface RawExtendedPrivateKey {
30
+ privateKey: Buffer;
31
+ chainCode: Buffer;
22
32
  }
23
33
  export interface OutputTarget {
24
34
  address?: string;
@@ -96,3 +106,36 @@ export interface P2SHInput {
96
106
  vout: any;
97
107
  outputScript: Buffer;
98
108
  }
109
+ export interface UsedUnusedAddressesResult {
110
+ usedAddresses: {
111
+ change: Address[];
112
+ external: Address[];
113
+ };
114
+ unusedAddress: {
115
+ change: Address | null;
116
+ external: Address | null;
117
+ };
118
+ }
119
+ /**
120
+ * Options for Yacoin sendTransaction and sendTransactionFixedInputs.
121
+ * Extends TransactionRequest with Yacoin-specific options.
122
+ */
123
+ export interface YacoinSendTransactionOptions extends TransactionRequest {
124
+ /**
125
+ * Pre-selected UTXOs to use as inputs. When set, only these UTXOs are used
126
+ * (e.g. for sendTransactionFixedInputs).
127
+ */
128
+ inputs?: UTXO[];
129
+ /**
130
+ * When true, use a change address (internal branch) for the change output;
131
+ * when false, use a receiving address (external branch). Default: false.
132
+ *
133
+ * NOTE: This only affects which branch is scanned for UTXOs and where
134
+ * the change output is sent; it does not alter token behavior.
135
+ */
136
+ change?: boolean;
137
+ /**
138
+ * Maximum number of addresses to scan for UTXOs. Default: 40.
139
+ */
140
+ addressLimit?: number;
141
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,4EAA4D;AAC5D,+CAA6B;AAsF7B,IAAY,WAEX;AAFD,WAAY,WAAW;IACnB,gCAAiB,CAAA;AACrB,CAAC,EAFW,WAAW,GAAX,mBAAW,KAAX,mBAAW,QAEtB;AAED,IAAY,QAEX;AAFD,WAAY,QAAQ;IAChB,yBAAa,CAAA;AACjB,CAAC,EAFW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAEnB"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,4EAA4D;AAC5D,+CAA6B;AAkG7B,IAAY,WAEX;AAFD,WAAY,WAAW;IACnB,gCAAiB,CAAA;AACrB,CAAC,EAFW,WAAW,GAAX,mBAAW,KAAX,mBAAW,QAEtB;AAED,IAAY,QAEX;AAFD,WAAY,QAAQ;IAChB,yBAAa,CAAA;AACjB,CAAC,EAFW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAEnB"}
@@ -1,11 +1,32 @@
1
1
  import { Chain, Wallet } from '@yaswap/client';
2
- import { Address, FeeType, Transaction, TransactionRequest } from '@yaswap/types';
3
- import { PsbtInputTarget } from '../types';
2
+ import { Address, FeeType, Transaction } from '@yaswap/types';
3
+ import { PsbtInputTarget, UsedUnusedAddressesResult, YacoinSendTransactionOptions } from '../types';
4
+ import { AddressSearchType } from './YacoinBaseWallet';
4
5
  export interface IYacoinWallet<T, S = any> extends Wallet<T, S> {
5
6
  getChainProvider(): Chain<T>;
6
- sendTransaction(txRequest: TransactionRequest): Promise<Transaction>;
7
+ sendTransaction(txRequest: YacoinSendTransactionOptions): Promise<Transaction>;
8
+ sendTransactionFixedInputs(options: YacoinSendTransactionOptions): Promise<Transaction>;
9
+ getTotalFeeFixedInputs(opts: YacoinSendTransactionOptions, max: boolean): Promise<number>;
7
10
  updateTransactionFee(tx: string | Transaction, newFee: FeeType): Promise<Transaction>;
8
11
  getWalletAddress(address: string): Promise<Address>;
9
12
  signPSBT(data: string, inputs: PsbtInputTarget[]): Promise<string>;
10
13
  signTx(transaction: string, hash: string, derivationPath: string, txfee: number): Promise<string>;
14
+ /**
15
+ * Get one unused receiving or change address.
16
+ *
17
+ * @param change When true, search change addresses; otherwise external/receiving.
18
+ * @param addressLimit Maximum number of address indexes to scan (per branch).
19
+ */
20
+ getUnusedAddress(change?: boolean, addressLimit?: number): Promise<Address | null>;
21
+ /**
22
+ * Get used addresses.
23
+ *
24
+ * @param addressType Which branch to scan: external, change or both. Defaults to both.
25
+ * @param addressLimit Maximum number of address indexes to scan (per branch).
26
+ */
27
+ getUsedAddresses(addressType?: AddressSearchType, addressLimit?: number): Promise<Address[]>;
28
+ /**
29
+ * Scan addresses and return both used and first unused addresses per branch.
30
+ */
31
+ getUsedUnusedAddresses(addressType: AddressSearchType, addressLimit?: number, gapLimit?: number): Promise<UsedUnusedAddressesResult>;
11
32
  }
@@ -4,8 +4,9 @@ import { Address, AddressType, Asset, Transaction, TransactionRequest, CreateTok
4
4
  import { BIP32Interface } from 'bip32';
5
5
  import { payments } from '@yaswap/yacoinjs-lib';
6
6
  import { YacoinBaseChainProvider } from '../chain/YacoinBaseChainProvider';
7
- import { AddressType as YaAddressType, YacoinNetwork, YacoinWalletProviderOptions, Input, OutputTarget, P2SHInput, PsbtInputTarget, Transaction as YaTransaction, UTXO } from '../types';
7
+ import { AddressType as YaAddressType, YacoinNetwork, YacoinWalletProviderOptions, OutputTarget, P2SHInput, PsbtInputTarget, Transaction as YaTransaction, UsedUnusedAddressesResult, UTXO, YacoinSendTransactionOptions } from '../types';
8
8
  import { CoinSelectTarget } from '../utils';
9
+ export declare const NUMBER_ADDRESS_LIMIT = 40;
9
10
  export declare enum AddressSearchType {
10
11
  EXTERNAL = 0,
11
12
  CHANGE = 1,
@@ -22,7 +23,7 @@ export declare abstract class YacoinBaseWalletProvider<T extends YacoinBaseChain
22
23
  constructor(options: YacoinWalletProviderOptions, chainProvider?: Chain<T>);
23
24
  protected onChainProviderUpdate(chainProvider: Chain<T>): void;
24
25
  protected abstract baseDerivationNode(): Promise<BIP32Interface>;
25
- protected abstract buildTransaction(targets: OutputTarget[], feePerByte?: number, fixedInputs?: Input[]): Promise<{
26
+ protected abstract buildTransaction(targets: OutputTarget[], feePerByte?: number, fixedUtxos?: UTXO[], change?: boolean, addressLimit?: number): Promise<{
26
27
  hex: string;
27
28
  fee: number;
28
29
  }>;
@@ -34,29 +35,54 @@ export declare abstract class YacoinBaseWalletProvider<T extends YacoinBaseChain
34
35
  abstract signTx(transaction: string, hash: string, derivationPath: string, txfee: number): Promise<string>;
35
36
  abstract signBatchP2SHTransaction(inputs: P2SHInput[], addresses: string, tx: any, lockTime?: number, segwit?: boolean): Promise<Buffer[]>;
36
37
  getDerivationCache(): DerivationCache;
37
- getUnusedAddress(change?: boolean): Promise<Address>;
38
- getUsedAddresses(): Promise<Address[]>;
38
+ /**
39
+ * Get one unused receiving or change address.
40
+ *
41
+ * @param change When true, search change addresses; otherwise external/receiving.
42
+ * @param addressLimit Maximum number of address indexes to scan (per branch). Defaults to NUMBER_ADDRESS_LIMIT.
43
+ * @returns The first unused address found or null if none within the limit.
44
+ */
45
+ getUnusedAddress(change?: boolean, addressLimit?: number): Promise<Address>;
46
+ /**
47
+ * Get used addresses.
48
+ *
49
+ * @param addressType Which branch to scan: external, change or both. Defaults to both.
50
+ * @param addressLimit Maximum number of address indexes to scan (per branch). Defaults to NUMBER_ADDRESS_LIMIT.
51
+ * @returns List of used addresses for the requested branch(es).
52
+ */
53
+ getUsedAddresses(addressType?: AddressSearchType, addressLimit?: number): Promise<Address[]>;
39
54
  getAddresses(startingIndex?: number, numAddresses?: number, change?: boolean): Promise<Address[]>;
40
55
  createToken(options: CreateTokenTransaction): Promise<Transaction>;
41
- sendTransaction(options: TransactionRequest): Promise<Transaction<YaTransaction>>;
42
- sendBatchTransaction(transactions: TransactionRequest[]): Promise<Transaction<YaTransaction>[]>;
56
+ sendTransaction(options: TransactionRequest & {
57
+ change?: boolean;
58
+ addressLimit?: number;
59
+ inputs?: UTXO[];
60
+ }): Promise<Transaction<YaTransaction>>;
61
+ sendTransactionFixedInputs(options: TransactionRequest & {
62
+ change?: boolean;
63
+ addressLimit?: number;
64
+ inputs?: UTXO[];
65
+ }): Promise<Transaction<YaTransaction>>;
66
+ sendBatchTransaction(transactions: (TransactionRequest & {
67
+ change?: boolean;
68
+ addressLimit?: number;
69
+ })[]): Promise<Transaction<YaTransaction>[]>;
43
70
  sendSweepTransaction(externalChangeAddress: AddressType, _asset: Asset, feePerByte: number): Promise<Transaction<YaTransaction>>;
44
71
  updateTransactionFee(tx: Transaction<YaTransaction> | string, newFeePerByte: number): Promise<Transaction<YaTransaction>>;
45
- getTotalFees(transactions: TransactionRequest[], max: boolean): Promise<any>;
46
- protected _sendTransaction(transactions: OutputTarget[], feePerByte?: number): Promise<Transaction<YaTransaction>>;
47
- protected findAddress(addresses: string[], change?: boolean): Promise<Address>;
72
+ getTotalFees(transactions: YacoinSendTransactionOptions[], max: boolean): Promise<any>;
73
+ protected _sendTransaction(transactions: OutputTarget[], feePerByte?: number, change?: boolean, addressLimit?: number, fixedUtxos?: UTXO[]): Promise<Transaction<YaTransaction>>;
74
+ protected findAddress(addresses: string[], change?: boolean, addressLimit?: number): Promise<Address>;
48
75
  getWalletAddress(address: string): Promise<Address>;
49
76
  protected getDerivationPathAddress(path: string): Promise<Address>;
50
- protected _getUsedUnusedAddresses(addressType: AddressSearchType): Promise<{
51
- usedAddresses: Address[];
52
- unusedAddress: {
53
- change: Address;
54
- external: Address;
55
- };
56
- }>;
77
+ getUsedUnusedAddresses(addressType: AddressSearchType, addressLimit?: number, gapLimit?: number): Promise<UsedUnusedAddressesResult>;
57
78
  protected withCachedUtxos(func: () => any): Promise<any>;
58
- protected getTotalFee(opts: TransactionRequest, max: boolean): Promise<number>;
59
- protected getInputsForAmount(_targets: OutputTarget[], feePerByte?: number, fixedInputs?: Input[], sweep?: boolean): Promise<{
79
+ getTotalFeeFixedInputs(opts: YacoinSendTransactionOptions, max: boolean): Promise<number>;
80
+ protected getTotalFee(opts: TransactionRequest & {
81
+ change?: boolean;
82
+ addressLimit?: number;
83
+ inputs?: UTXO[];
84
+ }, max: boolean): Promise<number>;
85
+ protected getInputsForAmount(_targets: OutputTarget[], feePerByte?: number, fixedUtxos?: UTXO[], sweep?: boolean, addressLimit?: number, change?: boolean): Promise<{
60
86
  inputs: UTXO[];
61
87
  coinChange: CoinSelectTarget;
62
88
  tokenChange: CoinSelectTarget;
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.YacoinBaseWalletProvider = exports.AddressSearchType = void 0;
15
+ exports.YacoinBaseWalletProvider = exports.AddressSearchType = exports.NUMBER_ADDRESS_LIMIT = void 0;
16
16
  const client_1 = require("@yaswap/client");
17
17
  const errors_1 = require("@yaswap/errors");
18
18
  const types_1 = require("@yaswap/types");
@@ -21,7 +21,7 @@ const yacoinjs_lib_1 = require("@yaswap/yacoinjs-lib");
21
21
  const memoizee_1 = __importDefault(require("memoizee"));
22
22
  const types_2 = require("../types");
23
23
  const utils_2 = require("../utils");
24
- const NUMBER_ADDRESS_LIMIT = 1;
24
+ exports.NUMBER_ADDRESS_LIMIT = 40;
25
25
  var AddressSearchType;
26
26
  (function (AddressSearchType) {
27
27
  AddressSearchType[AddressSearchType["EXTERNAL"] = 0] = "EXTERNAL";
@@ -56,16 +56,38 @@ class YacoinBaseWalletProvider extends client_1.Wallet {
56
56
  getDerivationCache() {
57
57
  return this._derivationCache;
58
58
  }
59
- getUnusedAddress(change = false) {
59
+ /**
60
+ * Get one unused receiving or change address.
61
+ *
62
+ * @param change When true, search change addresses; otherwise external/receiving.
63
+ * @param addressLimit Maximum number of address indexes to scan (per branch). Defaults to NUMBER_ADDRESS_LIMIT.
64
+ * @returns The first unused address found or null if none within the limit.
65
+ */
66
+ getUnusedAddress(change = false, addressLimit = exports.NUMBER_ADDRESS_LIMIT) {
60
67
  return __awaiter(this, void 0, void 0, function* () {
61
68
  const addressType = change ? AddressSearchType.CHANGE : AddressSearchType.EXTERNAL;
62
69
  const key = change ? 'change' : 'external';
63
- return this._getUsedUnusedAddresses(addressType).then(({ unusedAddress }) => unusedAddress[key]);
70
+ const { unusedAddress } = yield this.getUsedUnusedAddresses(addressType, addressLimit);
71
+ return unusedAddress[key];
64
72
  });
65
73
  }
66
- getUsedAddresses() {
74
+ /**
75
+ * Get used addresses.
76
+ *
77
+ * @param addressType Which branch to scan: external, change or both. Defaults to both.
78
+ * @param addressLimit Maximum number of address indexes to scan (per branch). Defaults to NUMBER_ADDRESS_LIMIT.
79
+ * @returns List of used addresses for the requested branch(es).
80
+ */
81
+ getUsedAddresses(addressType = AddressSearchType.EXTERNAL_OR_CHANGE, addressLimit = exports.NUMBER_ADDRESS_LIMIT) {
67
82
  return __awaiter(this, void 0, void 0, function* () {
68
- return this._getUsedUnusedAddresses(AddressSearchType.EXTERNAL_OR_CHANGE).then(({ usedAddresses }) => usedAddresses);
83
+ const result = yield this.getUsedUnusedAddresses(addressType, addressLimit);
84
+ if (addressType === AddressSearchType.EXTERNAL) {
85
+ return result.usedAddresses.external;
86
+ }
87
+ if (addressType === AddressSearchType.CHANGE) {
88
+ return result.usedAddresses.change;
89
+ }
90
+ return [...result.usedAddresses.change, ...result.usedAddresses.external];
69
91
  });
70
92
  }
71
93
  getAddresses(startingIndex = 0, numAddresses = 1, change = false) {
@@ -92,13 +114,35 @@ class YacoinBaseWalletProvider extends client_1.Wallet {
92
114
  });
93
115
  }
94
116
  sendTransaction(options) {
117
+ var _a, _b;
118
+ return __awaiter(this, void 0, void 0, function* () {
119
+ const change = (_a = options.change) !== null && _a !== void 0 ? _a : false;
120
+ const addressLimit = (_b = options.addressLimit) !== null && _b !== void 0 ? _b : exports.NUMBER_ADDRESS_LIMIT;
121
+ return this._sendTransaction(this.sendOptionsToOutputs([options]), options.fee, change, addressLimit, options.inputs);
122
+ });
123
+ }
124
+ sendTransactionFixedInputs(options) {
125
+ var _a, _b, _c;
95
126
  return __awaiter(this, void 0, void 0, function* () {
96
- return this._sendTransaction(this.sendOptionsToOutputs([options]), options.fee);
127
+ const targets = this.sendOptionsToOutputs([options]);
128
+ const fixedUtxos = (_a = options.inputs) !== null && _a !== void 0 ? _a : [];
129
+ const change = (_b = options.change) !== null && _b !== void 0 ? _b : false;
130
+ const addressLimit = (_c = options.addressLimit) !== null && _c !== void 0 ? _c : exports.NUMBER_ADDRESS_LIMIT;
131
+ const { hex, fee } = yield this.buildTransaction(targets, options.fee, fixedUtxos, change, addressLimit);
132
+ const result = yield this.chainProvider.sendRawTransaction(`data=${hex}`);
133
+ if (result == 'There was an error. Check your console.') {
134
+ throw new Error("Cannot send transaction, there might some reasons:\n 1) It might be the fee is not enough, please try increasing the fee.\n 2) The wallet haven't updated latest balance info, please wait 10 seconds and try again.");
135
+ }
136
+ return (0, utils_2.normalizeTransactionObject)((0, utils_2.decodeRawTransaction)(hex, this._network), fee);
97
137
  });
98
138
  }
99
139
  sendBatchTransaction(transactions) {
140
+ var _a, _b;
100
141
  return __awaiter(this, void 0, void 0, function* () {
101
- return [yield this._sendTransaction(this.sendOptionsToOutputs(transactions))];
142
+ const first = transactions[0];
143
+ const change = (_a = first === null || first === void 0 ? void 0 : first.change) !== null && _a !== void 0 ? _a : false;
144
+ const addressLimit = (_b = first === null || first === void 0 ? void 0 : first.addressLimit) !== null && _b !== void 0 ? _b : exports.NUMBER_ADDRESS_LIMIT;
145
+ return [yield this._sendTransaction(this.sendOptionsToOutputs(transactions), undefined, change, addressLimit)];
102
146
  });
103
147
  }
104
148
  sendSweepTransaction(externalChangeAddress, _asset, feePerByte) {
@@ -112,7 +156,21 @@ class YacoinBaseWalletProvider extends client_1.Wallet {
112
156
  return __awaiter(this, void 0, void 0, function* () {
113
157
  const txHash = typeof tx === 'string' ? tx : tx.hash;
114
158
  const transaction = (yield this.chainProvider.getTransactionByHash(txHash))._raw;
115
- const fixedInputs = [transaction.vin[0]]; // TODO: should this pick more than 1 input? RBF doesn't mandate it
159
+ const fixedUtxos = [];
160
+ for (const vin of transaction.vin) {
161
+ const txHex = yield this.chainProvider.getProvider().getRawTransactionByHash(vin.txid);
162
+ const txDecoded = (0, utils_2.decodeRawTransaction)(txHex, this._network);
163
+ const value = new types_1.BigNumber(txDecoded.vout[vin.vout].value).times(1e6).toNumber();
164
+ const address = txDecoded.vout[vin.vout].scriptPubKey.addresses[0];
165
+ const walletAddress = yield this.getWalletAddress(address);
166
+ fixedUtxos.push({
167
+ txid: vin.txid,
168
+ vout: vin.vout,
169
+ value,
170
+ address,
171
+ derivationPath: walletAddress.derivationPath,
172
+ });
173
+ }
116
174
  const lookupAddresses = transaction.vout.map((vout) => vout.scriptPubKey.addresses[0]);
117
175
  const changeAddress = yield this.findAddress(lookupAddresses, true);
118
176
  const changeOutput = transaction.vout.find((vout) => vout.scriptPubKey.addresses[0] === changeAddress.address);
@@ -125,8 +183,11 @@ class YacoinBaseWalletProvider extends client_1.Wallet {
125
183
  address: output.scriptPubKey.addresses[0],
126
184
  value: new types_1.BigNumber(output.value).times(1e6).toNumber(),
127
185
  }));
128
- const { hex, fee } = yield this.buildTransaction(transactions, newFeePerByte, fixedInputs);
129
- yield this.chainProvider.sendRawTransaction(`data=${hex}`);
186
+ const { hex, fee } = yield this.buildTransaction(transactions, newFeePerByte, fixedUtxos, true, exports.NUMBER_ADDRESS_LIMIT);
187
+ const result = yield this.chainProvider.sendRawTransaction(`data=${hex}`);
188
+ if (result == 'There was an error. Check your console.') {
189
+ throw new Error("Cannot send transaction, there might some reasons:\n 1) It might be the fee is not enough, please try increasing the fee.\n 2) The wallet haven't updated latest balance info, please wait 10 seconds and try again.");
190
+ }
130
191
  return (0, utils_2.normalizeTransactionObject)((0, utils_2.decodeRawTransaction)(hex, this._network), fee);
131
192
  });
132
193
  }
@@ -143,9 +204,9 @@ class YacoinBaseWalletProvider extends client_1.Wallet {
143
204
  return fees;
144
205
  });
145
206
  }
146
- _sendTransaction(transactions, feePerByte) {
207
+ _sendTransaction(transactions, feePerByte, change = false, addressLimit = exports.NUMBER_ADDRESS_LIMIT, fixedUtxos = []) {
147
208
  return __awaiter(this, void 0, void 0, function* () {
148
- const { hex, fee } = yield this.buildTransaction(transactions, feePerByte);
209
+ const { hex, fee } = yield this.buildTransaction(transactions, feePerByte, fixedUtxos, change, addressLimit);
149
210
  const result = yield this.chainProvider.sendRawTransaction(`data=${hex}`);
150
211
  if (result == 'There was an error. Check your console.') {
151
212
  throw new Error("Cannot send transaction, there might some reasons:\n 1) It might be the fee is not enough, please try increasing the fee.\n 2) The wallet haven't updated latest balance info, please wait 10 seconds and try again.");
@@ -153,11 +214,11 @@ class YacoinBaseWalletProvider extends client_1.Wallet {
153
214
  return (0, utils_2.normalizeTransactionObject)((0, utils_2.decodeRawTransaction)(hex, this._network), fee);
154
215
  });
155
216
  }
156
- findAddress(addresses, change = false) {
217
+ findAddress(addresses, change = false, addressLimit = exports.NUMBER_ADDRESS_LIMIT) {
157
218
  return __awaiter(this, void 0, void 0, function* () {
158
219
  // A maximum number of addresses to lookup after which it is deemed that the wallet does not contain this address
159
- const maxAddresses = NUMBER_ADDRESS_LIMIT;
160
- const addressesPerCall = 50;
220
+ const maxAddresses = addressLimit;
221
+ const addressesPerCall = exports.NUMBER_ADDRESS_LIMIT;
161
222
  let index = 0;
162
223
  while (index < maxAddresses) {
163
224
  const walletAddresses = yield this.getAddresses(index, addressesPerCall, change);
@@ -200,21 +261,71 @@ class YacoinBaseWalletProvider extends client_1.Wallet {
200
261
  return addressObject;
201
262
  });
202
263
  }
203
- _getUsedUnusedAddresses(addressType) {
264
+ getUsedUnusedAddresses(addressType, addressLimit = exports.NUMBER_ADDRESS_LIMIT, gapLimit = 1) {
204
265
  return __awaiter(this, void 0, void 0, function* () {
205
- const usedAddresses = [];
206
- const unusedAddressMap = { change: null, external: null };
207
- if (addressType === AddressSearchType.EXTERNAL_OR_CHANGE || addressType === AddressSearchType.EXTERNAL) {
208
- const externalAddresses = yield this.getAddresses(0, 1, false);
209
- const externalAddress = externalAddresses[0];
210
- usedAddresses.push(externalAddress);
211
- unusedAddressMap.external = externalAddress;
212
- }
213
- if (addressType === AddressSearchType.EXTERNAL_OR_CHANGE || addressType === AddressSearchType.CHANGE) {
214
- const changeAddresses = yield this.getAddresses(0, 1, true);
215
- const changeAddress = changeAddresses[0];
216
- usedAddresses.push(changeAddress);
217
- unusedAddressMap.change = changeAddress;
266
+ const usedAddresses = {
267
+ change: [],
268
+ external: [],
269
+ };
270
+ const unusedAddressMap = {
271
+ change: null,
272
+ external: null,
273
+ };
274
+ const consecutiveUnusedCount = { change: 0, external: 0 };
275
+ let numAddressAlreadyGet = 0;
276
+ const numAddressPerCall = 100;
277
+ let addressIndex = 0;
278
+ /* eslint-disable no-unmodified-loop-condition */
279
+ while (((addressType === AddressSearchType.EXTERNAL_OR_CHANGE &&
280
+ (consecutiveUnusedCount.change < gapLimit || consecutiveUnusedCount.external < gapLimit)) ||
281
+ (addressType === AddressSearchType.EXTERNAL && consecutiveUnusedCount.external < gapLimit) ||
282
+ (addressType === AddressSearchType.CHANGE && consecutiveUnusedCount.change < gapLimit)) &&
283
+ numAddressAlreadyGet < addressLimit) {
284
+ /* eslint-enable no-unmodified-loop-condition */
285
+ let addrList = [];
286
+ let changeAddresses = [];
287
+ let externalAddresses = [];
288
+ let maxBatchSize = 0;
289
+ if ((addressType === AddressSearchType.EXTERNAL_OR_CHANGE || addressType === AddressSearchType.CHANGE) &&
290
+ consecutiveUnusedCount.change < gapLimit &&
291
+ numAddressAlreadyGet < addressLimit) {
292
+ const remainingLimit = addressLimit - numAddressAlreadyGet;
293
+ const batchSize = Math.min(numAddressPerCall, remainingLimit);
294
+ changeAddresses = yield this.getAddresses(addressIndex, batchSize, true);
295
+ addrList = addrList.concat(changeAddresses);
296
+ maxBatchSize = Math.max(maxBatchSize, batchSize);
297
+ }
298
+ if ((addressType === AddressSearchType.EXTERNAL_OR_CHANGE || addressType === AddressSearchType.EXTERNAL) &&
299
+ consecutiveUnusedCount.external < gapLimit &&
300
+ numAddressAlreadyGet < addressLimit) {
301
+ const remainingLimit = addressLimit - numAddressAlreadyGet;
302
+ const batchSize = Math.min(numAddressPerCall, remainingLimit);
303
+ externalAddresses = yield this.getAddresses(addressIndex, batchSize, false);
304
+ addrList = addrList.concat(externalAddresses);
305
+ maxBatchSize = Math.max(maxBatchSize, batchSize);
306
+ }
307
+ if (addrList.length === 0) {
308
+ break;
309
+ }
310
+ const transactionCounts = yield this.chainProvider.getProvider().getAddressTransactionCounts(addrList);
311
+ for (const address of addrList) {
312
+ const isUsed = transactionCounts[address.toString()] > 0;
313
+ const isChangeAddress = changeAddresses.some((a) => address.toString() === a.toString());
314
+ const key = isChangeAddress ? 'change' : 'external';
315
+ if (isUsed) {
316
+ usedAddresses[key].push(address);
317
+ consecutiveUnusedCount[key] = 0;
318
+ unusedAddressMap[key] = null;
319
+ }
320
+ else {
321
+ consecutiveUnusedCount[key]++;
322
+ if (!unusedAddressMap[key]) {
323
+ unusedAddressMap[key] = address;
324
+ }
325
+ }
326
+ }
327
+ numAddressAlreadyGet += maxBatchSize;
328
+ addressIndex += maxBatchSize;
218
329
  }
219
330
  return {
220
331
  usedAddresses,
@@ -238,40 +349,47 @@ class YacoinBaseWalletProvider extends client_1.Wallet {
238
349
  return result;
239
350
  });
240
351
  }
352
+ getTotalFeeFixedInputs(opts, max) {
353
+ var _a, _b, _c;
354
+ return __awaiter(this, void 0, void 0, function* () {
355
+ const targets = this.sendOptionsToOutputs([opts]);
356
+ const addressLimit = (_a = opts.addressLimit) !== null && _a !== void 0 ? _a : exports.NUMBER_ADDRESS_LIMIT;
357
+ const useChangeUtxos = (_b = opts.change) !== null && _b !== void 0 ? _b : false;
358
+ const { fee } = yield this.getInputsForAmount(targets.filter((t) => !t.value), opts.fee, (_c = opts.inputs) !== null && _c !== void 0 ? _c : [], max, addressLimit, useChangeUtxos);
359
+ return fee;
360
+ });
361
+ }
241
362
  getTotalFee(opts, max) {
363
+ var _a, _b, _c, _d;
242
364
  return __awaiter(this, void 0, void 0, function* () {
243
365
  const targets = this.sendOptionsToOutputs([opts]);
244
366
  if (!max) {
245
- // const { fee } = await this.getInputsForAmount(targets, opts.fee as number);
246
- const { fee } = yield this.getInputsForAmount(targets, opts.fee);
367
+ const { fee } = yield this.getInputsForAmount(targets, opts.fee, [], false, (_a = opts.addressLimit) !== null && _a !== void 0 ? _a : exports.NUMBER_ADDRESS_LIMIT, (_b = opts.change) !== null && _b !== void 0 ? _b : false);
247
368
  return fee;
248
369
  }
249
370
  else {
250
- const { fee } = yield this.getInputsForAmount(targets.filter((t) => !t.value), opts.fee, [], true);
371
+ const { fee } = yield this.getInputsForAmount(targets.filter((t) => !t.value), opts.fee, [], true, (_c = opts.addressLimit) !== null && _c !== void 0 ? _c : exports.NUMBER_ADDRESS_LIMIT, (_d = opts.change) !== null && _d !== void 0 ? _d : false);
251
372
  return fee;
252
373
  }
253
374
  });
254
375
  }
255
- getInputsForAmount(_targets, feePerByte, fixedInputs = [], sweep = false) {
376
+ getInputsForAmount(_targets, feePerByte, fixedUtxos = [], sweep = false, addressLimit = exports.NUMBER_ADDRESS_LIMIT, change = false) {
256
377
  return __awaiter(this, void 0, void 0, function* () {
257
378
  const tokenTransferOutput = _targets.find((target) => target.tokenName !== undefined && target.tokenScriptType === types_1.TokenScriptType.transfer);
258
379
  const feePerBytePromise = this.chainProvider.getProvider().getFeePerByte();
259
380
  let utxos = [];
260
381
  let tokenUtxos = [];
261
- const addresses = yield this.getUsedAddresses();
262
- const fixedUtxos = [];
263
- if (fixedInputs.length > 0) {
264
- for (const input of fixedInputs) {
265
- const txHex = yield this.chainProvider.getProvider().getRawTransactionByHash(input.txid);
266
- const tx = (0, utils_2.decodeRawTransaction)(txHex, this._network);
267
- const value = new types_1.BigNumber(tx.vout[input.vout].value).times(1e6).toNumber();
268
- const address = tx.vout[input.vout].scriptPubKey.addresses[0];
269
- const walletAddress = yield this.getWalletAddress(address);
270
- const utxo = Object.assign(Object.assign({}, input), { value, address, derivationPath: walletAddress.derivationPath });
271
- fixedUtxos.push(utxo);
382
+ const addressType = change ? AddressSearchType.EXTERNAL_OR_CHANGE : AddressSearchType.EXTERNAL;
383
+ const addresses = yield this.getUsedAddresses(addressType, addressLimit);
384
+ const enrichedFixedUtxos = yield Promise.all(fixedUtxos.map((utxo) => __awaiter(this, void 0, void 0, function* () {
385
+ let derivationPath = utxo.derivationPath;
386
+ if (derivationPath === undefined) {
387
+ const walletAddress = yield this.getWalletAddress(utxo.address);
388
+ derivationPath = walletAddress.derivationPath;
272
389
  }
273
- }
274
- if (!sweep || fixedUtxos.length === 0) {
390
+ return Object.assign(Object.assign({}, utxo), { derivationPath });
391
+ })));
392
+ if (!sweep || enrichedFixedUtxos.length === 0) {
275
393
  const _utxos = yield this.chainProvider.getProvider().getUnspentTransactions(addresses);
276
394
  utxos.push(..._utxos.map((utxo) => {
277
395
  const addr = addresses.find((a) => a.address === utxo.address);
@@ -279,7 +397,7 @@ class YacoinBaseWalletProvider extends client_1.Wallet {
279
397
  }));
280
398
  }
281
399
  else {
282
- utxos = fixedUtxos;
400
+ utxos = enrichedFixedUtxos;
283
401
  }
284
402
  if (tokenTransferOutput) {
285
403
  const isNFTOutput = tokenTransferOutput.tokenName.indexOf('#') !== -1;