@yaswap/bitcoin 3.3.7 → 3.4.1

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,30 @@
1
1
  # @yaswap/bitcoin
2
2
 
3
+ ## 3.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Support HD wallet logic
8
+ - Updated dependencies
9
+ - @yaswap/client@3.4.1
10
+ - @yaswap/errors@3.4.1
11
+ - @yaswap/types@3.4.1
12
+ - @yaswap/utils@3.4.1
13
+
14
+ ## 3.4.0
15
+
16
+ ### Minor Changes
17
+
18
+ - Support HD wallet logic
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies
23
+ - @yaswap/client@3.4.0
24
+ - @yaswap/errors@3.4.0
25
+ - @yaswap/types@3.4.0
26
+ - @yaswap/utils@3.4.0
27
+
3
28
  ## 3.3.7
4
29
 
5
30
  ### Patch Changes
@@ -11,7 +11,7 @@ export { BitcoinSwapEsploraProvider } from './swap/BitcoinSwapEsploraProvider';
11
11
  export { BitcoinSwapRpcProvider } from './swap/BitcoinSwapRpcProvider';
12
12
  export * as BitcoinTypes from './types';
13
13
  export * as BitcoinUtils from './utils';
14
- export { BitcoinBaseWalletProvider } from './wallet/BitcoinBaseWallet';
14
+ export { AddressSearchType, BitcoinBaseWalletProvider, NUMBER_ADDRESS_LIMIT } from './wallet/BitcoinBaseWallet';
15
15
  export { BitcoinHDWalletProvider } from './wallet/BitcoinHDWallet';
16
16
  export { BitcoinNodeWalletProvider } from './wallet/BitcoinNodeWallet';
17
17
  export { BitcoinSingleWallet } from './wallet/BitcoinSingleWallet';
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.BitcoinSingleWallet = exports.BitcoinNodeWalletProvider = exports.BitcoinHDWalletProvider = exports.BitcoinBaseWalletProvider = exports.BitcoinUtils = exports.BitcoinTypes = exports.BitcoinSwapRpcProvider = exports.BitcoinSwapEsploraProvider = exports.BitcoinSwapBaseProvider = exports.BitcoinNetworks = exports.BitcoinFeeApiProvider = exports.BitcoinJsonRpcProvider = exports.BitcoinJsonRpcBaseProvider = exports.BitcoinEsploraBatchBaseProvider = exports.BitcoinEsploraBaseProvider = exports.BitcoinEsploraApiProvider = exports.BitcoinBaseChainProvider = void 0;
26
+ exports.BitcoinSingleWallet = exports.BitcoinNodeWalletProvider = exports.BitcoinHDWalletProvider = exports.NUMBER_ADDRESS_LIMIT = exports.BitcoinBaseWalletProvider = exports.AddressSearchType = exports.BitcoinUtils = exports.BitcoinTypes = exports.BitcoinSwapRpcProvider = exports.BitcoinSwapEsploraProvider = exports.BitcoinSwapBaseProvider = exports.BitcoinNetworks = exports.BitcoinFeeApiProvider = exports.BitcoinJsonRpcProvider = exports.BitcoinJsonRpcBaseProvider = exports.BitcoinEsploraBatchBaseProvider = exports.BitcoinEsploraBaseProvider = exports.BitcoinEsploraApiProvider = exports.BitcoinBaseChainProvider = void 0;
27
27
  var BitcoinBaseChainProvider_1 = require("./chain/BitcoinBaseChainProvider");
28
28
  Object.defineProperty(exports, "BitcoinBaseChainProvider", { enumerable: true, get: function () { return BitcoinBaseChainProvider_1.BitcoinBaseChainProvider; } });
29
29
  var BitcoinEsploraApiProvider_1 = require("./chain/esplora/BitcoinEsploraApiProvider");
@@ -49,7 +49,9 @@ Object.defineProperty(exports, "BitcoinSwapRpcProvider", { enumerable: true, get
49
49
  exports.BitcoinTypes = __importStar(require("./types"));
50
50
  exports.BitcoinUtils = __importStar(require("./utils"));
51
51
  var BitcoinBaseWallet_1 = require("./wallet/BitcoinBaseWallet");
52
+ Object.defineProperty(exports, "AddressSearchType", { enumerable: true, get: function () { return BitcoinBaseWallet_1.AddressSearchType; } });
52
53
  Object.defineProperty(exports, "BitcoinBaseWalletProvider", { enumerable: true, get: function () { return BitcoinBaseWallet_1.BitcoinBaseWalletProvider; } });
54
+ Object.defineProperty(exports, "NUMBER_ADDRESS_LIMIT", { enumerable: true, get: function () { return BitcoinBaseWallet_1.NUMBER_ADDRESS_LIMIT; } });
53
55
  var BitcoinHDWallet_1 = require("./wallet/BitcoinHDWallet");
54
56
  Object.defineProperty(exports, "BitcoinHDWalletProvider", { enumerable: true, get: function () { return BitcoinHDWallet_1.BitcoinHDWalletProvider; } });
55
57
  var BitcoinNodeWallet_1 = require("./wallet/BitcoinNodeWallet");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6EAA4E;AAAnE,oIAAA,wBAAwB,OAAA;AACjC,uFAAsF;AAA7E,sIAAA,yBAAyB,OAAA;AAClC,yFAAwF;AAA/E,wIAAA,0BAA0B,OAAA;AACnC,mGAAkG;AAAzF,kJAAA,+BAA+B,OAAA;AACxC,yFAAwF;AAA/E,wIAAA,0BAA0B,OAAA;AACnC,iFAAgF;AAAvE,gIAAA,sBAAsB,OAAA;AAC/B,qEAAoE;AAA3D,8HAAA,qBAAqB,OAAA;AAC9B,uCAA6C;AAApC,2GAAA,eAAe,OAAA;AACxB,0EAAyE;AAAhE,kIAAA,uBAAuB,OAAA;AAChC,gFAA+E;AAAtE,wIAAA,0BAA0B,OAAA;AACnC,wEAAuE;AAA9D,gIAAA,sBAAsB,OAAA;AAC/B,wDAAwC;AACxC,wDAAwC;AACxC,gEAAuE;AAA9D,8HAAA,yBAAyB,OAAA;AAClC,4DAAmE;AAA1D,0HAAA,uBAAuB,OAAA;AAChC,gEAAuE;AAA9D,8HAAA,yBAAyB,OAAA;AAClC,oEAAmE;AAA1D,0HAAA,mBAAmB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6EAA4E;AAAnE,oIAAA,wBAAwB,OAAA;AACjC,uFAAsF;AAA7E,sIAAA,yBAAyB,OAAA;AAClC,yFAAwF;AAA/E,wIAAA,0BAA0B,OAAA;AACnC,mGAAkG;AAAzF,kJAAA,+BAA+B,OAAA;AACxC,yFAAwF;AAA/E,wIAAA,0BAA0B,OAAA;AACnC,iFAAgF;AAAvE,gIAAA,sBAAsB,OAAA;AAC/B,qEAAoE;AAA3D,8HAAA,qBAAqB,OAAA;AAC9B,uCAA6C;AAApC,2GAAA,eAAe,OAAA;AACxB,0EAAyE;AAAhE,kIAAA,uBAAuB,OAAA;AAChC,gFAA+E;AAAtE,wIAAA,0BAA0B,OAAA;AACnC,wEAAuE;AAA9D,gIAAA,sBAAsB,OAAA;AAC/B,wDAAwC;AACxC,wDAAwC;AACxC,gEAAgH;AAAvG,sHAAA,iBAAiB,OAAA;AAAE,8HAAA,yBAAyB,OAAA;AAAE,yHAAA,oBAAoB,OAAA;AAC3E,4DAAmE;AAA1D,0HAAA,uBAAuB,OAAA;AAChC,gEAAuE;AAA9D,8HAAA,yBAAyB,OAAA;AAClC,oEAAmE;AAA1D,0HAAA,mBAAmB,OAAA"}
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { Network, TransactionRequest } from '@yaswap/types';
2
+ import { Address, Network, TransactionRequest } from '@yaswap/types';
3
3
  import { ECPairInterface, Network as BitcoinJsLibNetwork } from 'bitcoinjs-lib';
4
4
  export * as BitcoinEsploraTypes from './chain/esplora/types';
5
5
  export * as BitcoinJsonRpcTypes from './chain/jsonRpc/types';
@@ -18,8 +18,18 @@ export interface BitcoinSingleWalletOptions extends BitcoinNodeWalletOptions {
18
18
  export interface BitcoinWalletProviderOptions extends BitcoinNodeWalletOptions {
19
19
  baseDerivationPath: string;
20
20
  }
21
+ export interface RawExtendedPublicKey {
22
+ publicKey: Buffer;
23
+ chainCode: Buffer;
24
+ }
25
+ export interface RawExtendedPrivateKey {
26
+ privateKey: Buffer;
27
+ chainCode: Buffer;
28
+ }
21
29
  export interface BitcoinHDWalletProviderOptions extends BitcoinWalletProviderOptions {
22
- mnemonic: string;
30
+ mnemonic?: string;
31
+ extendedPublicKey?: RawExtendedPublicKey;
32
+ extendedPrivateKey?: RawExtendedPrivateKey;
23
33
  }
24
34
  export interface OutputTarget {
25
35
  address?: string;
@@ -86,6 +96,16 @@ export declare enum SwapMode {
86
96
  export declare type AddressTxCounts = {
87
97
  [index: string]: number;
88
98
  };
99
+ export interface UsedUnusedAddressesResult {
100
+ usedAddresses: {
101
+ change: Address[];
102
+ external: Address[];
103
+ };
104
+ unusedAddress: {
105
+ change: Address | null;
106
+ external: Address | null;
107
+ };
108
+ }
89
109
  export interface PsbtInputTarget {
90
110
  index: number;
91
111
  derivationPath: string;
@@ -96,6 +116,15 @@ export interface P2SHInput {
96
116
  vout: any;
97
117
  outputScript: Buffer;
98
118
  }
99
- export interface TransactionFixedInputRequest extends TransactionRequest {
119
+ /**
120
+ * Options for Bitcoin sendTransaction and sendTransactionFixedInputs.
121
+ * Extends TransactionRequest with Bitcoin-specific options.
122
+ */
123
+ export interface BitcoinSendTransactionOptions extends TransactionRequest {
124
+ /** Pre-selected UTXOs to use as inputs. When set, only these UTXOs are used (e.g. for sendTransactionFixedInputs). */
100
125
  inputs?: UTXO[];
126
+ /** When true, use a change address (internal branch) for the change output; when false, use a receiving address (external branch). Default: false. */
127
+ change?: boolean;
128
+ /** Maximum number of addresses to scan for UTXOs. Default: 40. */
129
+ addressLimit?: number;
101
130
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,6EAA6D;AAC7D,6EAA6D;AAC7D,+CAA6B;AAiF7B,IAAY,WAIX;AAJD,WAAY,WAAW;IACnB,gCAAiB,CAAA;IACjB,0CAA2B,CAAA;IAC3B,gCAAiB,CAAA;AACrB,CAAC,EAJW,WAAW,GAAX,mBAAW,KAAX,mBAAW,QAItB;AAED,IAAY,QAIX;AAJD,WAAY,QAAQ;IAChB,yBAAa,CAAA;IACb,sCAA0B,CAAA;IAC1B,2BAAe,CAAA;AACnB,CAAC,EAJW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAInB"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,6EAA6D;AAC7D,6EAA6D;AAC7D,+CAA6B;AA6F7B,IAAY,WAIX;AAJD,WAAY,WAAW;IACnB,gCAAiB,CAAA;IACjB,0CAA2B,CAAA;IAC3B,gCAAiB,CAAA;AACrB,CAAC,EAJW,WAAW,GAAX,mBAAW,KAAX,mBAAW,QAItB;AAED,IAAY,QAIX;AAJD,WAAY,QAAQ;IAChB,yBAAa,CAAA;IACb,sCAA0B,CAAA;IAC1B,2BAAe,CAAA;AACnB,CAAC,EAJW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAInB"}
@@ -1,11 +1,12 @@
1
1
  /// <reference types="node" />
2
2
  import { Chain, Wallet } from '@yaswap/client';
3
- import { Address, AddressType, Asset, Transaction, TransactionRequest, CreateTokenTransaction } from '@yaswap/types';
3
+ import { Address, AddressType, Asset, Transaction, CreateTokenTransaction } from '@yaswap/types';
4
4
  import { BIP32Interface } from 'bip32';
5
5
  import { payments } from 'bitcoinjs-lib';
6
6
  import { BitcoinBaseChainProvider } from '../chain/BitcoinBaseChainProvider';
7
- import { AddressType as BtcAddressType, BitcoinNetwork, BitcoinWalletProviderOptions, Input, OutputTarget, P2SHInput, PsbtInputTarget, Transaction as BtcTransaction, UTXO } from '../types';
7
+ import { AddressType as BtcAddressType, BitcoinNetwork, BitcoinSendTransactionOptions, BitcoinWalletProviderOptions, OutputTarget, P2SHInput, PsbtInputTarget, Transaction as BtcTransaction, UsedUnusedAddressesResult, UTXO } 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 BitcoinBaseWalletProvider<T extends BitcoinBaseCha
22
23
  constructor(options: BitcoinWalletProviderOptions, 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
  }>;
@@ -33,35 +34,45 @@ export declare abstract class BitcoinBaseWalletProvider<T extends BitcoinBaseCha
33
34
  abstract signPSBT(data: string, inputs: PsbtInputTarget[]): Promise<string>;
34
35
  abstract signBatchP2SHTransaction(inputs: P2SHInput[], addresses: string, tx: any, lockTime?: number, segwit?: boolean): Promise<Buffer[]>;
35
36
  getDerivationCache(): DerivationCache;
36
- getUnusedAddress(change?: boolean): Promise<Address>;
37
- getUsedAddresses(): Promise<Address[]>;
37
+ /**
38
+ * Get one unused receiving or change address.
39
+ *
40
+ * @param change When true, search change addresses; otherwise external/receiving.
41
+ * @param addressLimit Maximum number of address indexes to scan (per branch). Defaults to NUMBER_ADDRESS_LIMIT.
42
+ * @returns The first unused address found or null if none within the limit.
43
+ */
44
+ getUnusedAddress(change?: boolean, addressLimit?: number): Promise<Address>;
45
+ /**
46
+ * Get used addresses.
47
+ *
48
+ * @param addressType Which branch to scan: external, change or both. Defaults to both.
49
+ * @param addressLimit Maximum number of address indexes to scan (per branch). Defaults to NUMBER_ADDRESS_LIMIT.
50
+ * @returns List of used addresses for the requested branch(es).
51
+ */
52
+ getUsedAddresses(addressType?: AddressSearchType, addressLimit?: number): Promise<Address[]>;
38
53
  getAddresses(startingIndex?: number, numAddresses?: number, change?: boolean): Promise<Address[]>;
39
- createToken(txRequest: CreateTokenTransaction): Promise<null>;
40
- sendTransaction(options: TransactionRequest): Promise<Transaction<BtcTransaction>>;
41
- sendBatchTransaction(transactions: TransactionRequest[]): Promise<Transaction<BtcTransaction>[]>;
54
+ createToken(_txRequest: CreateTokenTransaction): Promise<null>;
55
+ sendTransactionFixedInputs(options: BitcoinSendTransactionOptions): Promise<Transaction<BtcTransaction>>;
56
+ sendTransaction(options: BitcoinSendTransactionOptions): Promise<Transaction<BtcTransaction>>;
57
+ sendBatchTransaction(transactions: BitcoinSendTransactionOptions[]): Promise<Transaction<BtcTransaction>[]>;
42
58
  sendSweepTransaction(externalChangeAddress: AddressType, _asset: Asset, feePerByte: number): Promise<Transaction<BtcTransaction>>;
43
59
  updateTransactionFee(tx: Transaction<BtcTransaction> | string, newFeePerByte: number): Promise<Transaction<BtcTransaction>>;
44
- getTotalFees(transactions: TransactionRequest[], max: boolean): Promise<any>;
45
- protected _sendTransaction(transactions: OutputTarget[], feePerByte?: number): Promise<Transaction<BtcTransaction>>;
46
- protected findAddress(addresses: string[], change?: boolean): Promise<Address>;
60
+ getTotalFees(transactions: BitcoinSendTransactionOptions[], max: boolean): Promise<any>;
61
+ protected _sendTransaction(transactions: OutputTarget[], feePerByte?: number, change?: boolean, addressLimit?: number): Promise<Transaction<BtcTransaction>>;
62
+ protected findAddress(addresses: string[], change?: boolean, addressLimit?: number): Promise<Address>;
47
63
  getWalletAddress(address: string): Promise<Address>;
48
64
  protected getDerivationPathAddress(path: string): Promise<Address>;
49
- protected _getUsedUnusedAddresses(addressType: AddressSearchType): Promise<{
50
- usedAddresses: Address[];
51
- unusedAddress: {
52
- change: Address;
53
- external: Address;
54
- };
55
- }>;
65
+ getUsedUnusedAddresses(addressType: AddressSearchType, addressLimit?: number, gapLimit?: number): Promise<UsedUnusedAddressesResult>;
56
66
  protected withCachedUtxos(func: () => any): Promise<any>;
57
- protected getTotalFee(opts: TransactionRequest, max: boolean): Promise<number>;
58
- protected getInputsForAmount(_targets: OutputTarget[], feePerByte?: number, fixedInputs?: Input[], sweep?: boolean): Promise<{
67
+ getTotalFeeFixedInputs(opts: BitcoinSendTransactionOptions, max: boolean): Promise<number>;
68
+ protected getTotalFee(opts: BitcoinSendTransactionOptions, max: boolean): Promise<number>;
69
+ protected getInputsForAmount(_targets: OutputTarget[], feePerByte?: number, fixedUtxos?: UTXO[], sweep?: boolean, addressLimit?: number, change?: boolean): Promise<{
59
70
  inputs: UTXO[];
60
71
  change: CoinSelectTarget;
61
72
  outputs: CoinSelectTarget[];
62
73
  fee: number;
63
74
  }>;
64
- protected sendOptionsToOutputs(transactions: TransactionRequest[]): OutputTarget[];
75
+ protected sendOptionsToOutputs(transactions: BitcoinSendTransactionOptions[]): OutputTarget[];
65
76
  protected getAddressFromPublicKey(publicKey: Buffer): string;
66
77
  protected getPaymentVariantFromPublicKey(publicKey: Buffer): payments.Payment;
67
78
  }
@@ -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.BitcoinBaseWalletProvider = exports.AddressSearchType = void 0;
15
+ exports.BitcoinBaseWalletProvider = 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");
@@ -22,7 +22,7 @@ const memoizee_1 = __importDefault(require("memoizee"));
22
22
  const types_2 = require("../types");
23
23
  const utils_2 = require("../utils");
24
24
  const utils_3 = __importDefault(require("@yaswap/bitcoinselect/utils"));
25
- const NUMBER_ADDRESS_LIMIT = 1;
25
+ exports.NUMBER_ADDRESS_LIMIT = 40;
26
26
  var AddressSearchType;
27
27
  (function (AddressSearchType) {
28
28
  AddressSearchType[AddressSearchType["EXTERNAL"] = 0] = "EXTERNAL";
@@ -48,16 +48,38 @@ class BitcoinBaseWalletProvider extends client_1.Wallet {
48
48
  getDerivationCache() {
49
49
  return this._derivationCache;
50
50
  }
51
- getUnusedAddress(change = false) {
51
+ /**
52
+ * Get one unused receiving or change address.
53
+ *
54
+ * @param change When true, search change addresses; otherwise external/receiving.
55
+ * @param addressLimit Maximum number of address indexes to scan (per branch). Defaults to NUMBER_ADDRESS_LIMIT.
56
+ * @returns The first unused address found or null if none within the limit.
57
+ */
58
+ getUnusedAddress(change = false, addressLimit = exports.NUMBER_ADDRESS_LIMIT) {
52
59
  return __awaiter(this, void 0, void 0, function* () {
53
60
  const addressType = change ? AddressSearchType.CHANGE : AddressSearchType.EXTERNAL;
54
61
  const key = change ? 'change' : 'external';
55
- return this._getUsedUnusedAddresses(addressType).then(({ unusedAddress }) => unusedAddress[key]);
62
+ const { unusedAddress } = yield this.getUsedUnusedAddresses(addressType, addressLimit);
63
+ return unusedAddress[key];
56
64
  });
57
65
  }
58
- getUsedAddresses() {
66
+ /**
67
+ * Get used addresses.
68
+ *
69
+ * @param addressType Which branch to scan: external, change or both. Defaults to both.
70
+ * @param addressLimit Maximum number of address indexes to scan (per branch). Defaults to NUMBER_ADDRESS_LIMIT.
71
+ * @returns List of used addresses for the requested branch(es).
72
+ */
73
+ getUsedAddresses(addressType = AddressSearchType.EXTERNAL_OR_CHANGE, addressLimit = exports.NUMBER_ADDRESS_LIMIT) {
59
74
  return __awaiter(this, void 0, void 0, function* () {
60
- return this._getUsedUnusedAddresses(AddressSearchType.EXTERNAL_OR_CHANGE).then(({ usedAddresses }) => usedAddresses);
75
+ const result = yield this.getUsedUnusedAddresses(addressType, addressLimit);
76
+ if (addressType === AddressSearchType.EXTERNAL) {
77
+ return result.usedAddresses.external;
78
+ }
79
+ if (addressType === AddressSearchType.CHANGE) {
80
+ return result.usedAddresses.change;
81
+ }
82
+ return [...result.usedAddresses.change, ...result.usedAddresses.external];
61
83
  });
62
84
  }
63
85
  getAddresses(startingIndex = 0, numAddresses = 1, change = false) {
@@ -78,19 +100,38 @@ class BitcoinBaseWalletProvider extends client_1.Wallet {
78
100
  return addresses;
79
101
  });
80
102
  }
81
- createToken(txRequest) {
103
+ createToken(_txRequest) {
82
104
  return __awaiter(this, void 0, void 0, function* () {
83
105
  return null;
84
106
  });
85
107
  }
108
+ sendTransactionFixedInputs(options) {
109
+ var _a, _b, _c;
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ const targets = this.sendOptionsToOutputs([options]);
112
+ const fixedUtxos = (_a = options.inputs) !== null && _a !== void 0 ? _a : [];
113
+ const change = (_b = options.change) !== null && _b !== void 0 ? _b : false;
114
+ const addressLimit = (_c = options.addressLimit) !== null && _c !== void 0 ? _c : exports.NUMBER_ADDRESS_LIMIT;
115
+ const { hex, fee } = yield this.buildTransaction(targets, options.fee, fixedUtxos, change, addressLimit);
116
+ yield this.chainProvider.sendRawTransaction(hex);
117
+ return (0, utils_2.normalizeTransactionObject)((0, utils_2.decodeRawTransaction)(hex, this._network), fee);
118
+ });
119
+ }
86
120
  sendTransaction(options) {
121
+ var _a, _b;
87
122
  return __awaiter(this, void 0, void 0, function* () {
88
- return this._sendTransaction(this.sendOptionsToOutputs([options]), options.fee);
123
+ const change = (_a = options.change) !== null && _a !== void 0 ? _a : false;
124
+ const addressLimit = (_b = options.addressLimit) !== null && _b !== void 0 ? _b : exports.NUMBER_ADDRESS_LIMIT;
125
+ return this._sendTransaction(this.sendOptionsToOutputs([options]), options.fee, change, addressLimit);
89
126
  });
90
127
  }
91
128
  sendBatchTransaction(transactions) {
129
+ var _a, _b;
92
130
  return __awaiter(this, void 0, void 0, function* () {
93
- return [yield this._sendTransaction(this.sendOptionsToOutputs(transactions))];
131
+ const first = transactions[0];
132
+ const change = (_a = first === null || first === void 0 ? void 0 : first.change) !== null && _a !== void 0 ? _a : false;
133
+ const addressLimit = (_b = first === null || first === void 0 ? void 0 : first.addressLimit) !== null && _b !== void 0 ? _b : exports.NUMBER_ADDRESS_LIMIT;
134
+ return [yield this._sendTransaction(this.sendOptionsToOutputs(transactions), undefined, change, addressLimit)];
94
135
  });
95
136
  }
96
137
  sendSweepTransaction(externalChangeAddress, _asset, feePerByte) {
@@ -104,7 +145,23 @@ class BitcoinBaseWalletProvider extends client_1.Wallet {
104
145
  return __awaiter(this, void 0, void 0, function* () {
105
146
  const txHash = typeof tx === 'string' ? tx : tx.hash;
106
147
  const transaction = (yield this.chainProvider.getTransactionByHash(txHash))._raw;
107
- const fixedInputs = [transaction.vin[0]]; // TODO: should this pick more than 1 input? RBF doesn't mandate it
148
+ const fixedUtxos = [];
149
+ const needsWitness = [types_2.AddressType.BECH32, types_2.AddressType.P2SH_SEGWIT].includes(this._addressType);
150
+ for (const vin of transaction.vin) {
151
+ const txHex = yield this.chainProvider.getProvider().getRawTransactionByHash(vin.txid);
152
+ const tx = (0, utils_2.decodeRawTransaction)(txHex, this._network);
153
+ const value = new types_1.BigNumber(tx.vout[vin.vout].value).times(1e8).toNumber();
154
+ const address = tx.vout[vin.vout].scriptPubKey.addresses[0];
155
+ const walletAddress = yield this.getWalletAddress(address);
156
+ fixedUtxos.push({
157
+ txid: vin.txid,
158
+ vout: vin.vout,
159
+ value,
160
+ address,
161
+ derivationPath: walletAddress.derivationPath,
162
+ witnessUtxo: needsWitness ? { script: new Uint8Array(0), value } : null,
163
+ });
164
+ }
108
165
  const lookupAddresses = transaction.vout.map((vout) => vout.scriptPubKey.addresses[0]);
109
166
  const changeAddress = yield this.findAddress(lookupAddresses, true);
110
167
  const changeOutput = transaction.vout.find((vout) => vout.scriptPubKey.addresses[0] === changeAddress.address);
@@ -117,7 +174,7 @@ class BitcoinBaseWalletProvider extends client_1.Wallet {
117
174
  address: output.scriptPubKey.addresses[0],
118
175
  value: new types_1.BigNumber(output.value).times(1e8).toNumber(),
119
176
  }));
120
- const { hex, fee } = yield this.buildTransaction(transactions, newFeePerByte, fixedInputs);
177
+ const { hex, fee } = yield this.buildTransaction(transactions, newFeePerByte, fixedUtxos, true, exports.NUMBER_ADDRESS_LIMIT);
121
178
  yield this.chainProvider.sendRawTransaction(hex);
122
179
  return (0, utils_2.normalizeTransactionObject)((0, utils_2.decodeRawTransaction)(hex, this._network), fee);
123
180
  });
@@ -140,18 +197,18 @@ class BitcoinBaseWalletProvider extends client_1.Wallet {
140
197
  return fees;
141
198
  });
142
199
  }
143
- _sendTransaction(transactions, feePerByte) {
200
+ _sendTransaction(transactions, feePerByte, change = false, addressLimit = exports.NUMBER_ADDRESS_LIMIT) {
144
201
  return __awaiter(this, void 0, void 0, function* () {
145
- const { hex, fee } = yield this.buildTransaction(transactions, feePerByte);
202
+ const { hex, fee } = yield this.buildTransaction(transactions, feePerByte, [], change, addressLimit);
146
203
  yield this.chainProvider.sendRawTransaction(hex);
147
204
  return (0, utils_2.normalizeTransactionObject)((0, utils_2.decodeRawTransaction)(hex, this._network), fee);
148
205
  });
149
206
  }
150
- findAddress(addresses, change = false) {
207
+ findAddress(addresses, change = false, addressLimit = exports.NUMBER_ADDRESS_LIMIT) {
151
208
  return __awaiter(this, void 0, void 0, function* () {
152
209
  // A maximum number of addresses to lookup after which it is deemed that the wallet does not contain this address
153
- const maxAddresses = NUMBER_ADDRESS_LIMIT;
154
- const addressesPerCall = 50;
210
+ const maxAddresses = addressLimit;
211
+ const addressesPerCall = exports.NUMBER_ADDRESS_LIMIT;
155
212
  let index = 0;
156
213
  while (index < maxAddresses) {
157
214
  const walletAddresses = yield this.getAddresses(index, addressesPerCall, change);
@@ -194,21 +251,75 @@ class BitcoinBaseWalletProvider extends client_1.Wallet {
194
251
  return addressObject;
195
252
  });
196
253
  }
197
- _getUsedUnusedAddresses(addressType) {
254
+ getUsedUnusedAddresses(addressType, addressLimit = exports.NUMBER_ADDRESS_LIMIT, gapLimit = 1) {
198
255
  return __awaiter(this, void 0, void 0, function* () {
199
- const usedAddresses = [];
200
- const unusedAddressMap = { change: null, external: null };
201
- if (addressType === AddressSearchType.EXTERNAL_OR_CHANGE || addressType === AddressSearchType.EXTERNAL) {
202
- const externalAddresses = yield this.getAddresses(0, 1, false);
203
- const externalAddress = externalAddresses[0];
204
- usedAddresses.push(externalAddress);
205
- unusedAddressMap.external = externalAddress;
206
- }
207
- if (addressType === AddressSearchType.EXTERNAL_OR_CHANGE || addressType === AddressSearchType.CHANGE) {
208
- const changeAddresses = yield this.getAddresses(0, 1, true);
209
- const changeAddress = changeAddresses[0];
210
- usedAddresses.push(changeAddress);
211
- unusedAddressMap.change = changeAddress;
256
+ const usedAddresses = {
257
+ change: [],
258
+ external: [],
259
+ };
260
+ const unusedAddressMap = {
261
+ change: null,
262
+ external: null,
263
+ };
264
+ const consecutiveUnusedCount = { change: 0, external: 0 };
265
+ let numAddressAlreadyGet = 0;
266
+ const numAddressPerCall = 100;
267
+ let addressIndex = 0;
268
+ /* eslint-disable no-unmodified-loop-condition */
269
+ while (((addressType === AddressSearchType.EXTERNAL_OR_CHANGE &&
270
+ (consecutiveUnusedCount.change < gapLimit || consecutiveUnusedCount.external < gapLimit)) ||
271
+ (addressType === AddressSearchType.EXTERNAL && consecutiveUnusedCount.external < gapLimit) ||
272
+ (addressType === AddressSearchType.CHANGE && consecutiveUnusedCount.change < gapLimit)) &&
273
+ numAddressAlreadyGet < addressLimit) {
274
+ /* eslint-enable no-unmodified-loop-condition */
275
+ let addrList = [];
276
+ let changeAddresses = [];
277
+ let externalAddresses = [];
278
+ let maxBatchSize = 0;
279
+ if ((addressType === AddressSearchType.EXTERNAL_OR_CHANGE || addressType === AddressSearchType.CHANGE) &&
280
+ consecutiveUnusedCount.change < gapLimit &&
281
+ numAddressAlreadyGet < addressLimit) {
282
+ // Scanning for change addr
283
+ const remainingLimit = addressLimit - numAddressAlreadyGet;
284
+ const batchSize = Math.min(numAddressPerCall, remainingLimit);
285
+ changeAddresses = yield this.getAddresses(addressIndex, batchSize, true);
286
+ addrList = addrList.concat(changeAddresses);
287
+ maxBatchSize = Math.max(maxBatchSize, batchSize);
288
+ }
289
+ if ((addressType === AddressSearchType.EXTERNAL_OR_CHANGE || addressType === AddressSearchType.EXTERNAL) &&
290
+ consecutiveUnusedCount.external < gapLimit &&
291
+ numAddressAlreadyGet < addressLimit) {
292
+ // Scanning for non change addr
293
+ const remainingLimit = addressLimit - numAddressAlreadyGet;
294
+ const batchSize = Math.min(numAddressPerCall, remainingLimit);
295
+ externalAddresses = yield this.getAddresses(addressIndex, batchSize, false);
296
+ addrList = addrList.concat(externalAddresses);
297
+ maxBatchSize = Math.max(maxBatchSize, batchSize);
298
+ }
299
+ if (addrList.length === 0) {
300
+ break;
301
+ }
302
+ const transactionCounts = yield this.chainProvider
303
+ .getProvider()
304
+ .getAddressTransactionCounts(addrList);
305
+ for (const address of addrList) {
306
+ const isUsed = transactionCounts[address.toString()] > 0;
307
+ const isChangeAddress = changeAddresses.some((a) => address.toString() === a.toString());
308
+ const key = isChangeAddress ? 'change' : 'external';
309
+ if (isUsed) {
310
+ usedAddresses[key].push(address);
311
+ consecutiveUnusedCount[key] = 0;
312
+ unusedAddressMap[key] = null;
313
+ }
314
+ else {
315
+ consecutiveUnusedCount[key]++;
316
+ if (!unusedAddressMap[key]) {
317
+ unusedAddressMap[key] = address;
318
+ }
319
+ }
320
+ }
321
+ numAddressAlreadyGet += maxBatchSize;
322
+ addressIndex += maxBatchSize;
212
323
  }
213
324
  return {
214
325
  usedAddresses,
@@ -232,47 +343,64 @@ class BitcoinBaseWalletProvider extends client_1.Wallet {
232
343
  return result;
233
344
  });
234
345
  }
346
+ getTotalFeeFixedInputs(opts, max) {
347
+ var _a, _b, _c;
348
+ return __awaiter(this, void 0, void 0, function* () {
349
+ const targets = this.sendOptionsToOutputs([opts]);
350
+ const addressLimit = (_a = opts.addressLimit) !== null && _a !== void 0 ? _a : exports.NUMBER_ADDRESS_LIMIT;
351
+ const useChangeUtxos = (_b = opts.change) !== null && _b !== void 0 ? _b : false;
352
+ const { fee } = yield this.getInputsForAmount(targets.filter((t) => !t.value), opts.fee, (_c = opts.inputs) !== null && _c !== void 0 ? _c : [], max, addressLimit, useChangeUtxos);
353
+ return fee;
354
+ });
355
+ }
235
356
  getTotalFee(opts, max) {
357
+ var _a, _b;
236
358
  return __awaiter(this, void 0, void 0, function* () {
237
359
  const targets = this.sendOptionsToOutputs([opts]);
360
+ const addressLimit = (_a = opts.addressLimit) !== null && _a !== void 0 ? _a : exports.NUMBER_ADDRESS_LIMIT;
361
+ const useChangeUtxos = (_b = opts.change) !== null && _b !== void 0 ? _b : false;
238
362
  if (!max) {
239
- const { fee } = yield this.getInputsForAmount(targets, opts.fee);
363
+ const { fee } = yield this.getInputsForAmount(targets, opts.fee, [], false, addressLimit, useChangeUtxos);
240
364
  return fee;
241
365
  }
242
366
  else {
243
- const { fee } = yield this.getInputsForAmount(targets.filter((t) => !t.value), opts.fee, [], true);
367
+ const { fee } = yield this.getInputsForAmount(targets.filter((t) => !t.value), opts.fee, [], true, addressLimit, useChangeUtxos);
244
368
  return fee;
245
369
  }
246
370
  });
247
371
  }
248
- getInputsForAmount(_targets, feePerByte, fixedInputs = [], sweep = false) {
372
+ getInputsForAmount(_targets, feePerByte, fixedUtxos = [], sweep = false, addressLimit = exports.NUMBER_ADDRESS_LIMIT, change = false) {
249
373
  return __awaiter(this, void 0, void 0, function* () {
250
374
  const feePerBytePromise = this.chainProvider.getProvider().getFeePerByte();
251
375
  const utxos = [];
252
- const addresses = yield this.getUsedAddresses();
253
- const fixedUtxos = [];
376
+ const addressType = change ? AddressSearchType.EXTERNAL_OR_CHANGE : AddressSearchType.EXTERNAL;
377
+ const addresses = yield this.getUsedAddresses(addressType, addressLimit);
254
378
  const needsWitness = [types_2.AddressType.BECH32, types_2.AddressType.P2SH_SEGWIT].includes(this._addressType);
255
- if (fixedInputs.length > 0) {
256
- for (const input of fixedInputs) {
257
- const txHex = yield this.chainProvider.getProvider().getRawTransactionByHash(input.txid);
258
- const tx = (0, utils_2.decodeRawTransaction)(txHex, this._network);
259
- const value = new types_1.BigNumber(tx.vout[input.vout].value).times(1e8).toNumber();
260
- const address = tx.vout[input.vout].scriptPubKey.addresses[0];
261
- const walletAddress = yield this.getWalletAddress(address);
262
- const utxo = Object.assign(Object.assign({}, input), { value, address, derivationPath: walletAddress.derivationPath, witnessUtxo: needsWitness ? { script: new Uint8Array(0), value } : null });
263
- fixedUtxos.push(utxo);
379
+ // Enrich fixedUtxos that are missing derivationPath or witnessUtxo
380
+ const enrichedFixedUtxos = yield Promise.all(fixedUtxos.map((utxo) => __awaiter(this, void 0, void 0, function* () {
381
+ let derivationPath = utxo.derivationPath;
382
+ if (derivationPath === undefined) {
383
+ const walletAddress = yield this.getWalletAddress(utxo.address);
384
+ derivationPath = walletAddress.derivationPath;
264
385
  }
265
- }
266
- if (!sweep || fixedUtxos.length === 0) {
386
+ const witnessUtxo = utxo.witnessUtxo !== undefined
387
+ ? utxo.witnessUtxo
388
+ : needsWitness
389
+ ? { script: new Uint8Array(0), value: utxo.value }
390
+ : null;
391
+ return Object.assign(Object.assign({}, utxo), { derivationPath, witnessUtxo });
392
+ })));
393
+ if (!sweep || enrichedFixedUtxos.length === 0) {
267
394
  const _utxos = yield this.chainProvider.getProvider().getUnspentTransactions(addresses);
268
395
  utxos.push(..._utxos.map((utxo) => {
269
396
  const addr = addresses.find((a) => a.address === utxo.address);
270
- return Object.assign(Object.assign({}, utxo), { witnessUtxo: needsWitness ? { script: new Uint8Array(0), value: utxo.value } : null, derivationPath: addr.derivationPath });
397
+ return Object.assign(Object.assign({}, utxo), { witnessUtxo: needsWitness ? { script: new Uint8Array(0), value: utxo.value } : null, derivationPath: addr === null || addr === void 0 ? void 0 : addr.derivationPath });
271
398
  }));
272
399
  }
273
400
  else {
274
- utxos.push(...fixedUtxos.map((utxo) => {
275
- return Object.assign(Object.assign({}, utxo), { witnessUtxo: needsWitness ? { script: new Uint8Array(0), value: utxo.value } : null });
401
+ utxos.push(...enrichedFixedUtxos.map((utxo) => {
402
+ var _a;
403
+ return (Object.assign(Object.assign({}, utxo), { witnessUtxo: (_a = utxo.witnessUtxo) !== null && _a !== void 0 ? _a : (needsWitness ? { script: new Uint8Array(0), value: utxo.value } : null) }));
276
404
  }));
277
405
  }
278
406
  const utxoBalance = utxos.reduce((a, b) => a + (b.value || 0), 0);
@@ -307,11 +435,11 @@ class BitcoinBaseWalletProvider extends client_1.Wallet {
307
435
  else {
308
436
  targets = _targets.map((target) => ({ id: 'main', value: target.value, script: target.script, address: target.address }));
309
437
  }
310
- const { inputs, outputs, change, fee } = (0, utils_2.selectCoins)(utxos, targets, Math.ceil(feePerByte));
438
+ const { inputs, outputs, change: changeOutput, fee } = (0, utils_2.selectCoins)(utxos, targets, Math.ceil(feePerByte));
311
439
  if (inputs && outputs) {
312
440
  return {
313
441
  inputs,
314
- change,
442
+ change: changeOutput,
315
443
  outputs,
316
444
  fee,
317
445
  };