@bitcoinerlab/descriptors 1.0.1 → 1.1.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/README.md CHANGED
@@ -106,7 +106,7 @@ constructor({
106
106
  // of tx size (if more than one path is available).
107
107
  // For more details on using this parameter, refer to this
108
108
  // Stack Exchange answer: https://bitcoin.stackexchange.com/a/118036/89665
109
- }: DescriptorInfo);
109
+ });
110
110
  ```
111
111
 
112
112
  The `Descriptor` class offers various helpful methods, including `getAddress()`, which returns the address associated with the descriptor, `getScriptPubKey()`, which returns the scriptPubKey for the descriptor, `expand()`, which decomposes a descriptor into its elemental parts, `updatePsbt()` and `finalizePsbt()`.
@@ -1,15 +1,149 @@
1
+ /// <reference types="node" />
2
+ import { Network, Payment, Psbt } from 'bitcoinjs-lib';
3
+ import type { PartialSig } from 'bip174/src/lib/interfaces';
1
4
  import { BIP32API } from 'bip32';
2
5
  import { ECPairAPI } from 'ecpair';
3
- import type { TinySecp256k1Interface, ParseKeyExpression, Expand, DescriptorInterfaceConstructor } from './types';
6
+ import type { TinySecp256k1Interface, Preimage, TimeConstraints, ExpansionMap, Expand, ParseKeyExpression } from './types';
4
7
  /**
5
8
  * Builds the functions needed to operate with descriptors using an external elliptic curve (ecc) library.
6
9
  * @param {Object} ecc - an object containing elliptic curve operations, such as [tiny-secp256k1](https://github.com/bitcoinjs/tiny-secp256k1) or [@bitcoinerlab/secp256k1](https://github.com/bitcoinerlab/secp256k1).
7
- * @namespace
8
10
  */
9
11
  export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
10
- Descriptor: DescriptorInterfaceConstructor;
11
- ECPair: ECPairAPI;
12
+ Descriptor: {
13
+ new ({ expression, index, checksumRequired, allowMiniscriptInP2SH, network, preimages, signersPubKeys }: {
14
+ /**
15
+ * The descriptor string in ASCII format. It may include a "*" to denote an arbitrary index.
16
+ */
17
+ expression: string;
18
+ /**
19
+ * The descriptor's index in the case of a range descriptor (must be an integer >=0).
20
+ */
21
+ index?: number;
22
+ /**
23
+ * A flag indicating whether the descriptor is required to include a checksum.
24
+ * @defaultValue false
25
+ */
26
+ checksumRequired?: boolean;
27
+ /**
28
+ * A flag indicating whether this instance can parse and generate script satisfactions for sh(miniscript) top-level expressions of miniscripts. This is not recommended.
29
+ * @defaultValue false
30
+ */
31
+ allowMiniscriptInP2SH?: boolean;
32
+ /**
33
+ * One of bitcoinjs-lib [`networks`](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/networks.js) (or another one following the same interface).
34
+ * @defaultValue networks.bitcoin
35
+ */
36
+ network?: Network;
37
+ /**
38
+ * An array of preimages. This info is necessary to finalize Psbts.
39
+ * @defaultValue `[]`
40
+ */
41
+ preimages?: Preimage[];
42
+ /**
43
+ * An array of the public keys used for signing the transaction when spending the output associated with this descriptor. This parameter is only used if the descriptor object is being used to finalize a transaction. It is necessary to specify the spending path when working with miniscript-based expressions that have multiple spending paths. Set this parameter to an array containing the public keys involved in the desired spending path. Leave it `undefined` if you only need to generate the `scriptPubKey` or `address` for a descriptor, or if all the public keys involved in the descriptor will sign the transaction. In the latter case, the satisfier will automatically choose the most optimal spending path (if more than one is available).
44
+ */
45
+ signersPubKeys?: Buffer[];
46
+ }): {
47
+ readonly "__#1@#payment": Payment;
48
+ readonly "__#1@#preimages": Preimage[];
49
+ readonly "__#1@#signersPubKeys": Buffer[];
50
+ readonly "__#1@#miniscript"?: string;
51
+ readonly "__#1@#witnessScript"?: Buffer;
52
+ readonly "__#1@#redeemScript"?: Buffer;
53
+ readonly "__#1@#isSegwit"?: boolean;
54
+ readonly "__#1@#expandedExpression"?: string;
55
+ readonly "__#1@#expandedMiniscript"?: string;
56
+ readonly "__#1@#expansionMap"?: ExpansionMap;
57
+ readonly "__#1@#network": Network;
58
+ /**
59
+ * Gets the TimeConstraints (nSequence and nLockTime) of the miniscript
60
+ * descriptor as passed in the constructor, just using the expression,
61
+ * the signersPubKeys and preimages.
62
+ *
63
+ * We just need to know which will be the signatures that will be
64
+ * used (signersPubKeys) but final signatures are not necessary for
65
+ * obtaning nLockTime and nSequence.
66
+ *
67
+ * Remember: nSequence and nLockTime are part of the hash that is signed.
68
+ * Thus, they must not change after computing the signatures.
69
+ * When running getScriptSatisfaction, using the final signatures,
70
+ * satisfyMiniscript verifies that the time constraints did not change.
71
+ */
72
+ "__#1@#getTimeConstraints"(): TimeConstraints | undefined;
73
+ getPayment(): Payment;
74
+ /**
75
+ * Returns the Bitcoin Address
76
+ */
77
+ getAddress(): string;
78
+ getScriptPubKey(): Buffer;
79
+ /**
80
+ * Returns the compiled script satisfaction
81
+ * @param {PartialSig[]} signatures An array of signatures using this format: `interface PartialSig { pubkey: Buffer; signature: Buffer; }`
82
+ * @returns {Buffer}
83
+ */
84
+ getScriptSatisfaction(signatures: PartialSig[]): Buffer;
85
+ getSequence(): number | undefined;
86
+ getLockTime(): number | undefined;
87
+ getWitnessScript(): Buffer | undefined;
88
+ getRedeemScript(): Buffer | undefined;
89
+ getNetwork(): Network;
90
+ isSegwit(): boolean | undefined;
91
+ /**
92
+ * Updates a Psbt where the descriptor describes an utxo.
93
+ * The txHex (nonWitnessUtxo) and vout of the utxo must be passed.
94
+ *
95
+ * updatePsbt adds an input to the psbt and updates the tx locktime if needed.
96
+ * It also adds a new input to the Psbt based on txHex
97
+ * It returns the number of the input that is added.
98
+ * psbt and vout are mandatory. Also pass txHex.
99
+ *
100
+ * The following is not recommended but, alternatively, ONLY for Segwit inputs,
101
+ * you can pass txId and value, instead of txHex.
102
+ * If you do so, it is your responsibility to make sure that `value` is
103
+ * correct to avoid possible fee vulnerability attacks:
104
+ * https://github.com/bitcoinjs/bitcoinjs-lib/issues/1625
105
+ * Note that HW wallets require the full txHex also for Segwit anyways:
106
+ * https://blog.trezor.io/details-of-firmware-updates-for-trezor-one-version-1-9-1-and-trezor-model-t-version-2-3-1-1eba8f60f2dd
107
+ *
108
+ * In doubt, simply pass txHex (and you can skip passing txId and value) and
109
+ * you shall be fine.
110
+ */
111
+ updatePsbt({ psbt, txHex, txId, value, vout }: {
112
+ psbt: Psbt;
113
+ txHex?: string;
114
+ txId?: string;
115
+ value?: number;
116
+ vout: number;
117
+ }): number;
118
+ "__#1@#assertPsbtInput"({ psbt, index }: {
119
+ psbt: Psbt;
120
+ index: number;
121
+ }): void;
122
+ finalizePsbtInput({ index, psbt, validate }: {
123
+ index: number;
124
+ psbt: Psbt;
125
+ validate?: boolean | undefined;
126
+ }): void;
127
+ expand(): {
128
+ expansionMap?: ExpansionMap;
129
+ expandedMiniscript?: string;
130
+ miniscript?: string;
131
+ expandedExpression?: string;
132
+ };
133
+ };
134
+ };
12
135
  parseKeyExpression: ParseKeyExpression;
13
136
  expand: Expand;
137
+ ECPair: ECPairAPI;
14
138
  BIP32: BIP32API;
15
139
  };
140
+ /**
141
+ * The {@link DescriptorsFactory | `DescriptorsFactory`} function internally creates and returns the {@link _Internal_.Descriptor | `Descriptor`} class.
142
+ * This class is specialized for the provided `TinySecp256k1Interface`.
143
+ * Use `DescriptorInstance` to declare instances for this class: `const: DescriptorInstance = new Descriptor();`
144
+ *
145
+ * See the {@link _Internal_.Descriptor | documentation for the internal Descriptor class} for a complete list of available methods.
146
+ */
147
+ type DescriptorConstructor = ReturnType<typeof DescriptorsFactory>['Descriptor'];
148
+ type DescriptorInstance = InstanceType<DescriptorConstructor>;
149
+ export { DescriptorInstance, DescriptorConstructor };
@@ -95,14 +95,13 @@ function evaluate({ expression, checksumRequired, index }) {
95
95
  /**
96
96
  * Builds the functions needed to operate with descriptors using an external elliptic curve (ecc) library.
97
97
  * @param {Object} ecc - an object containing elliptic curve operations, such as [tiny-secp256k1](https://github.com/bitcoinjs/tiny-secp256k1) or [@bitcoinerlab/secp256k1](https://github.com/bitcoinerlab/secp256k1).
98
- * @namespace
99
98
  */
100
99
  function DescriptorsFactory(ecc) {
101
100
  var _Descriptor_instances, _Descriptor_payment, _Descriptor_preimages, _Descriptor_signersPubKeys, _Descriptor_miniscript, _Descriptor_witnessScript, _Descriptor_redeemScript, _Descriptor_isSegwit, _Descriptor_expandedExpression, _Descriptor_expandedMiniscript, _Descriptor_expansionMap, _Descriptor_network, _Descriptor_getTimeConstraints, _Descriptor_assertPsbtInput;
102
101
  const BIP32 = (0, bip32_1.BIP32Factory)(ecc);
103
102
  const ECPair = (0, ecpair_1.ECPairFactory)(ecc);
104
103
  const signatureValidator = (pubkey, msghash, signature) => ECPair.fromPublicKey(pubkey).verify(msghash, signature);
105
- /*
104
+ /**
106
105
  * Takes a string key expression (xpub, xprv, pubkey or wif) and parses it
107
106
  */
108
107
  const parseKeyExpression = ({ keyExpression, isSegwit, network = bitcoinjs_lib_1.networks.bitcoin }) => {
@@ -117,27 +116,6 @@ function DescriptorsFactory(ecc) {
117
116
  /**
118
117
  * Takes a descriptor (expression) and expands it to its corresponding Bitcoin script and other relevant details.
119
118
  *
120
- * @param {Object} params The parameters for the function.
121
- * @param {string} params.expression The descriptor expression to be expanded.
122
- * @param {string} [params.loggedExpression] The descriptor expression used for logging error messages. If not provided, defaults to the original expression.
123
- * @param {Object} [params.network=networks.bitcoin] The Bitcoin network to use. If not provided, defaults to Bitcoin mainnet.
124
- * @param {boolean} [params.allowMiniscriptInP2SH=false] Flag to allow miniscript in P2SH. If not provided, defaults to false.
125
- *
126
- * @returns {Object} An object containing various details about the expanded descriptor:
127
- * - payment: The corresponding [bitcoinjs-lib Payment](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/payments/index.ts) for the provided expression, if applicable.
128
- * - expandedExpression: The expanded descriptor expression.
129
- * - miniscript: The extracted miniscript from the expression, if any.
130
- * - expansionMap: A map of key expressions in the descriptor to their corresponding expanded keys.
131
- * - isSegwit: A boolean indicating whether the descriptor represents a SegWit script.
132
- * - expandedMiniscript: The expanded miniscript, if any.
133
- * - redeemScript: The redeem script for the descriptor, if applicable.
134
- * - witnessScript: The witness script for the descriptor, if applicable.
135
- * - isRanged: Whether this expression representas a ranged-descriptor
136
- * - canonicalExpression: This is the preferred or authoritative
137
- * representation of the descriptor expression. It standardizes the
138
- * descriptor by replacing indexes on wildcards and eliminating checksums.
139
- * This helps ensure consistency and facilitates efficient interpretation and handling by systems or software.
140
- *
141
119
  * @throws {Error} Throws an error if the descriptor cannot be parsed or does not conform to the expected format.
142
120
  */
143
121
  const expand = ({ expression, index, checksumRequired = false, network = bitcoinjs_lib_1.networks.bitcoin, allowMiniscriptInP2SH = false }) => {
@@ -399,15 +377,7 @@ function DescriptorsFactory(ecc) {
399
377
  }
400
378
  class Descriptor {
401
379
  /**
402
- * @param {DescriptorInfo} params
403
- * @param {string} params.expression - The descriptor string in ASCII format. It may include a "*" to denote an arbitrary index.
404
- * @param {number} params.index - The descriptor's index in the case of a range descriptor (must be an interger >=0).
405
- * @param {boolean} [params.checksumRequired=false] - A flag indicating whether the descriptor is required to include a checksum.
406
- * @param {boolean} [params.allowMiniscriptInP2SH=false] - A flag indicating whether this instance can parse and generate script satisfactions for sh(miniscript) top-level expressions of miniscripts. This is not recommended.
407
- * @param {object} [params.network=networks.bitcoin] One of bitcoinjs-lib [`networks`](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/networks.js) (or another one following the same interface).
408
- * @param {Preimage[]} [params.preimages=[]] An array of preimages. This info is necessary to finalize Psbts.
409
- * @param {Buffer[]} [params.signersPubKeys] (Optional): An array of the public keys used for signing the transaction when spending the output associated with this descriptor. This parameter is only used if the descriptor object is being used to finalize a transaction. It is necessary to specify the spending path when working with miniscript-based expressions that have multiple spending paths. Set this parameter to an array containing the public keys involved in the desired spending path. Leave it `undefined` if you only need to generate the `scriptPubKey` or `address` for a descriptor, or if all the public keys involved in the descriptor will sign the transaction. In the latter case, the satisfier will automatically choose the most optimal spending path (if more than one is available).
410
- *
380
+ * @param options
411
381
  * @throws {Error} - when descriptor is invalid
412
382
  */
413
383
  constructor({ expression, index, checksumRequired = false, allowMiniscriptInP2SH = false, network = bitcoinjs_lib_1.networks.bitcoin, preimages = [], signersPubKeys }) {
package/dist/index.d.ts CHANGED
@@ -1,13 +1,13 @@
1
+ export type { KeyInfo, Expansion } from './types';
1
2
  import type { Psbt } from 'bitcoinjs-lib';
2
- import type { DescriptorInterface } from './types';
3
- export { DescriptorInterface, DescriptorInterfaceConstructor, ParseKeyExpression } from './types';
4
- export { DescriptorsFactory } from './descriptors';
3
+ import type { DescriptorInstance } from './descriptors';
4
+ export { DescriptorsFactory, DescriptorInstance, DescriptorConstructor } from './descriptors';
5
5
  export { DescriptorChecksum as checksum } from './checksum';
6
6
  import * as signers from './signers';
7
7
  export { signers };
8
8
  export declare function finalizePsbt({ psbt, descriptors, validate }: {
9
9
  psbt: Psbt;
10
- descriptors: DescriptorInterface[];
10
+ descriptors: DescriptorInstance[];
11
11
  validate?: boolean | undefined;
12
12
  }): void;
13
13
  export { keyExpressionBIP32, keyExpressionLedger } from './keyExpressions';
package/dist/index.js CHANGED
@@ -26,7 +26,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
26
26
  };
27
27
  Object.defineProperty(exports, "__esModule", { value: true });
28
28
  exports.ledger = exports.scriptExpressions = exports.keyExpressionLedger = exports.keyExpressionBIP32 = exports.finalizePsbt = exports.signers = exports.checksum = exports.DescriptorsFactory = void 0;
29
- var types_1 = require("./types");
30
29
  var descriptors_1 = require("./descriptors");
31
30
  Object.defineProperty(exports, "DescriptorsFactory", { enumerable: true, get: function () { return descriptors_1.DescriptorsFactory; } });
32
31
  var checksum_1 = require("./checksum");
@@ -3,9 +3,17 @@ import type { ECPairAPI } from 'ecpair';
3
3
  import type { BIP32API, BIP32Interface } from 'bip32';
4
4
  import type { KeyInfo } from './types';
5
5
  import { LedgerState } from './ledger';
6
+ /**
7
+ * Parses a key expression (xpub, xprv, pubkey or wif) into KeyInfo
8
+ */
6
9
  export declare function parseKeyExpression({ keyExpression, isSegwit, ECPair, BIP32, network }: {
7
10
  keyExpression: string;
8
11
  network?: Network;
12
+ /**
13
+ * Indicates if this is a SegWit key expression. When set, further checks
14
+ * ensure the public key (if present in the expression) is compressed
15
+ * (33 bytes).
16
+ */
9
17
  isSegwit?: boolean;
10
18
  ECPair: ECPairAPI;
11
19
  BIP32: BIP32API;
@@ -43,7 +43,7 @@ const derivePath = (node, path) => {
43
43
  }
44
44
  return node.derivePath(parsedPath);
45
45
  };
46
- /*
46
+ /**
47
47
  * Parses a key expression (xpub, xprv, pubkey or wif) into KeyInfo
48
48
  */
49
49
  function parseKeyExpression({ keyExpression, isSegwit, ECPair, BIP32, network = bitcoinjs_lib_1.networks.bitcoin }) {
package/dist/ledger.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import type { DescriptorInterface } from './types';
2
+ import type { DescriptorInstance } from './descriptors';
3
3
  /**
4
4
  * Dynamically imports the 'ledger-bitcoin' module and, if provided, checks if `ledgerClient` is an instance of `AppClient`.
5
5
  *
@@ -7,7 +7,7 @@ import type { DescriptorInterface } from './types';
7
7
  * @param {unknown} ledgerClient - An optional parameter that, if provided, is checked to see if it's an instance of `AppClient`.
8
8
  * @throws {Error} Throws an error if `ledgerClient` is provided but is not an instance of `AppClient`.
9
9
  * @throws {Error} Throws an error if the 'ledger-bitcoin' module cannot be imported. This typically indicates that the 'ledger-bitcoin' peer dependency is not installed.
10
- * @returns {Promise<any>} Returns a promise that resolves with the entire 'ledger-bitcoin' module if it can be successfully imported.
10
+ * @returns {Promise<unknown>} Returns a promise that resolves with the entire 'ledger-bitcoin' module if it can be successfully imported. We force it to return an unknown type so that the declaration of this function won't break projects that don't use ledger-bitcoin as dependency
11
11
  *
12
12
  * @example
13
13
  *
@@ -18,7 +18,7 @@ import type { DescriptorInterface } from './types';
18
18
  * })
19
19
  * .catch((error) => console.error(error));
20
20
  */
21
- export declare function importAndValidateLedgerBitcoin(ledgerClient?: unknown): Promise<typeof import("ledger-bitcoin")>;
21
+ export declare function importAndValidateLedgerBitcoin(ledgerClient?: unknown): Promise<unknown>;
22
22
  export declare function assertLedgerApp({ transport, name, minVersion }: {
23
23
  transport: any;
24
24
  name: string;
@@ -73,7 +73,7 @@ export declare function getLedgerXpub({ originPath, ledgerClient, ledgerState }:
73
73
  * policy implementation details expressed in the header of this file.
74
74
  */
75
75
  export declare function descriptorToLedgerFormat({ descriptor, ledgerClient, ledgerState }: {
76
- descriptor: DescriptorInterface;
76
+ descriptor: DescriptorInstance;
77
77
  ledgerClient: unknown;
78
78
  ledgerState: LedgerState;
79
79
  }): Promise<{
@@ -88,7 +88,7 @@ export declare function descriptorToLedgerFormat({ descriptor, ledgerClient, led
88
88
  *
89
89
  **/
90
90
  export declare function registerLedgerWallet({ descriptor, ledgerClient, ledgerState, policyName }: {
91
- descriptor: DescriptorInterface;
91
+ descriptor: DescriptorInstance;
92
92
  ledgerClient: unknown;
93
93
  ledgerState: LedgerState;
94
94
  policyName: string;
@@ -97,7 +97,7 @@ export declare function registerLedgerWallet({ descriptor, ledgerClient, ledgerS
97
97
  * Retrieve a standard ledger policy or null if it does correspond.
98
98
  **/
99
99
  export declare function ledgerPolicyFromStandard({ descriptor, ledgerClient, ledgerState }: {
100
- descriptor: DescriptorInterface;
100
+ descriptor: DescriptorInstance;
101
101
  ledgerClient: unknown;
102
102
  ledgerState: LedgerState;
103
103
  }): Promise<LedgerPolicy | null>;
@@ -106,7 +106,7 @@ export declare function comparePolicies(policyA: LedgerPolicy, policyB: LedgerPo
106
106
  * Retrieve a ledger policy from ledgerState or null if it does not exist yet.
107
107
  **/
108
108
  export declare function ledgerPolicyFromState({ descriptor, ledgerClient, ledgerState }: {
109
- descriptor: DescriptorInterface;
109
+ descriptor: DescriptorInstance;
110
110
  ledgerClient: unknown;
111
111
  ledgerState: LedgerState;
112
112
  }): Promise<LedgerPolicy | null>;
package/dist/ledger.js CHANGED
@@ -1,29 +1,6 @@
1
1
  "use strict";
2
2
  // Copyright (c) 2023 Jose-Luis Landabaso - https://bitcoinerlab.com
3
3
  // Distributed under the MIT software license
4
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
- if (k2 === undefined) k2 = k;
6
- var desc = Object.getOwnPropertyDescriptor(m, k);
7
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
- desc = { enumerable: true, get: function() { return m[k]; } };
9
- }
10
- Object.defineProperty(o, k2, desc);
11
- }) : (function(o, m, k, k2) {
12
- if (k2 === undefined) k2 = k;
13
- o[k2] = m[k];
14
- }));
15
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
- Object.defineProperty(o, "default", { enumerable: true, value: v });
17
- }) : function(o, v) {
18
- o["default"] = v;
19
- });
20
- var __importStar = (this && this.__importStar) || function (mod) {
21
- if (mod && mod.__esModule) return mod;
22
- var result = {};
23
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
24
- __setModuleDefault(result, mod);
25
- return result;
26
- };
27
4
  Object.defineProperty(exports, "__esModule", { value: true });
28
5
  exports.ledgerPolicyFromState = exports.comparePolicies = exports.ledgerPolicyFromStandard = exports.registerLedgerWallet = exports.descriptorToLedgerFormat = exports.getLedgerXpub = exports.getLedgerMasterFingerPrint = exports.assertLedgerApp = exports.importAndValidateLedgerBitcoin = void 0;
29
6
  const bitcoinjs_lib_1 = require("bitcoinjs-lib");
@@ -35,7 +12,7 @@ const re_1 = require("./re");
35
12
  * @param {unknown} ledgerClient - An optional parameter that, if provided, is checked to see if it's an instance of `AppClient`.
36
13
  * @throws {Error} Throws an error if `ledgerClient` is provided but is not an instance of `AppClient`.
37
14
  * @throws {Error} Throws an error if the 'ledger-bitcoin' module cannot be imported. This typically indicates that the 'ledger-bitcoin' peer dependency is not installed.
38
- * @returns {Promise<any>} Returns a promise that resolves with the entire 'ledger-bitcoin' module if it can be successfully imported.
15
+ * @returns {Promise<unknown>} Returns a promise that resolves with the entire 'ledger-bitcoin' module if it can be successfully imported. We force it to return an unknown type so that the declaration of this function won't break projects that don't use ledger-bitcoin as dependency
39
16
  *
40
17
  * @example
41
18
  *
@@ -49,7 +26,18 @@ const re_1 = require("./re");
49
26
  async function importAndValidateLedgerBitcoin(ledgerClient) {
50
27
  let ledgerBitcoinModule;
51
28
  try {
52
- ledgerBitcoinModule = await Promise.resolve().then(() => __importStar(require('ledger-bitcoin')));
29
+ // Originally, the code used dynamic imports:
30
+ // ledgerBitcoinModule = await import('ledger-bitcoin');
31
+ // However, in React Native with the Metro bundler, there's an issue with
32
+ // recognizing dynamic imports inside try-catch blocks. For details, refer to:
33
+ // https://github.com/react-native-community/discussions-and-proposals/issues/120
34
+ // The dynamic import gets transpiled to:
35
+ // ledgerBitcoinModule = Promise.resolve().then(() => __importStar(require('ledger-bitcoin')));
36
+ // Metro bundler fails to recognize the above as conditional. Hence, it tries
37
+ // to require 'ledger-bitcoin' unconditionally, leading to potential errors if
38
+ // 'ledger-bitcoin' is not installed (given it's an optional peerDependency).
39
+ // To bypass this, we directly use require:
40
+ ledgerBitcoinModule = require('ledger-bitcoin');
53
41
  }
54
42
  catch (error) {
55
43
  throw new Error('Could not import "ledger-bitcoin". This is a peer dependency and needs to be installed explicitly. Please run "npm install ledger-bitcoin" to use Ledger Hardware Wallet functionality.');
@@ -115,7 +103,7 @@ function isLedgerStandard({ ledgerTemplate, keyRoots, network = bitcoinjs_lib_1.
115
103
  return false;
116
104
  }
117
105
  async function getLedgerMasterFingerPrint({ ledgerClient, ledgerState }) {
118
- const { AppClient } = await importAndValidateLedgerBitcoin(ledgerClient);
106
+ const { AppClient } = (await importAndValidateLedgerBitcoin(ledgerClient));
119
107
  if (!(ledgerClient instanceof AppClient))
120
108
  throw new Error(`Error: pass a valid ledgerClient`);
121
109
  let masterFingerprint = ledgerState.masterFingerprint;
@@ -127,7 +115,7 @@ async function getLedgerMasterFingerPrint({ ledgerClient, ledgerState }) {
127
115
  }
128
116
  exports.getLedgerMasterFingerPrint = getLedgerMasterFingerPrint;
129
117
  async function getLedgerXpub({ originPath, ledgerClient, ledgerState }) {
130
- const { AppClient } = await importAndValidateLedgerBitcoin(ledgerClient);
118
+ const { AppClient } = (await importAndValidateLedgerBitcoin(ledgerClient));
131
119
  if (!(ledgerClient instanceof AppClient))
132
120
  throw new Error(`Error: pass a valid ledgerClient`);
133
121
  if (!ledgerState.xpubs)
@@ -242,7 +230,7 @@ exports.descriptorToLedgerFormat = descriptorToLedgerFormat;
242
230
  *
243
231
  **/
244
232
  async function registerLedgerWallet({ descriptor, ledgerClient, ledgerState, policyName }) {
245
- const { WalletPolicy, AppClient } = await importAndValidateLedgerBitcoin(ledgerClient);
233
+ const { WalletPolicy, AppClient } = (await importAndValidateLedgerBitcoin(ledgerClient));
246
234
  if (!(ledgerClient instanceof AppClient))
247
235
  throw new Error(`Error: pass a valid ledgerClient`);
248
236
  const result = await descriptorToLedgerFormat({
package/dist/signers.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Psbt } from 'bitcoinjs-lib';
2
2
  import type { ECPairInterface } from 'ecpair';
3
3
  import type { BIP32Interface } from 'bip32';
4
- import type { DescriptorInterface } from './types';
4
+ import type { DescriptorInstance } from './descriptors';
5
5
  import { LedgerState } from './ledger';
6
6
  export declare function signInputECPair({ psbt, index, ecpair }: {
7
7
  psbt: Psbt;
@@ -24,13 +24,13 @@ export declare function signBIP32({ psbt, masterNode }: {
24
24
  export declare function signInputLedger({ psbt, index, descriptor, ledgerClient, ledgerState }: {
25
25
  psbt: Psbt;
26
26
  index: number;
27
- descriptor: DescriptorInterface;
27
+ descriptor: DescriptorInstance;
28
28
  ledgerClient: unknown;
29
29
  ledgerState: LedgerState;
30
30
  }): Promise<void>;
31
31
  export declare function signLedger({ psbt, descriptors, ledgerClient, ledgerState }: {
32
32
  psbt: Psbt;
33
- descriptors: DescriptorInterface[];
33
+ descriptors: DescriptorInstance[];
34
34
  ledgerClient: unknown;
35
35
  ledgerState: LedgerState;
36
36
  }): Promise<void>;
package/dist/signers.js CHANGED
@@ -27,7 +27,7 @@ const ledgerSignaturesForInputIndex = (index, ledgerSignatures) => ledgerSignatu
27
27
  signature: partialSignature.signature
28
28
  }));
29
29
  async function signInputLedger({ psbt, index, descriptor, ledgerClient, ledgerState }) {
30
- const { PsbtV2, DefaultWalletPolicy, WalletPolicy, AppClient } = await (0, ledger_1.importAndValidateLedgerBitcoin)(ledgerClient);
30
+ const { PsbtV2, DefaultWalletPolicy, WalletPolicy, AppClient } = (await (0, ledger_1.importAndValidateLedgerBitcoin)(ledgerClient));
31
31
  if (!(ledgerClient instanceof AppClient))
32
32
  throw new Error(`Error: pass a valid ledgerClient`);
33
33
  const result = await (0, ledger_1.descriptorToLedgerFormat)({
@@ -68,7 +68,7 @@ exports.signInputLedger = signInputLedger;
68
68
  //it clusters together wallet policy types before signing
69
69
  //it throws if it cannot sign any input.
70
70
  async function signLedger({ psbt, descriptors, ledgerClient, ledgerState }) {
71
- const { PsbtV2, DefaultWalletPolicy, WalletPolicy, AppClient } = await (0, ledger_1.importAndValidateLedgerBitcoin)(ledgerClient);
71
+ const { PsbtV2, DefaultWalletPolicy, WalletPolicy, AppClient } = (await (0, ledger_1.importAndValidateLedgerBitcoin)(ledgerClient));
72
72
  if (!(ledgerClient instanceof AppClient))
73
73
  throw new Error(`Error: pass a valid ledgerClient`);
74
74
  const ledgerPolicies = [];
package/dist/types.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import type { ECPairInterface } from 'ecpair';
3
3
  import type { BIP32Interface } from 'bip32';
4
- import type { Network, Payment, Psbt } from 'bitcoinjs-lib';
5
- import type { PartialSig } from 'bip174/src/lib/interfaces';
4
+ import type { Payment, Network } from 'bitcoinjs-lib';
6
5
  /**
7
6
  * Preimage
8
7
  * @alias Preimage
@@ -37,37 +36,12 @@ export type KeyInfo = {
37
36
  export type ExpansionMap = {
38
37
  [key: string]: KeyInfo;
39
38
  };
40
- export interface ParseKeyExpression {
41
- (params: {
42
- keyExpression: string;
43
- isSegwit?: boolean;
44
- network?: Network;
45
- }): KeyInfo;
46
- }
47
- export interface Expand {
48
- (params: {
49
- expression: string;
50
- index?: number;
51
- checksumRequired?: boolean;
52
- network?: Network;
53
- allowMiniscriptInP2SH?: boolean;
54
- }): {
55
- payment?: Payment;
56
- expandedExpression?: string;
57
- miniscript?: string;
58
- expansionMap?: ExpansionMap;
59
- isSegwit?: boolean;
60
- expandedMiniscript?: string;
61
- redeemScript?: Buffer;
62
- witnessScript?: Buffer;
63
- isRanged: boolean;
64
- canonicalExpression: string;
65
- };
66
- }
39
+ /** @ignore */
67
40
  interface XOnlyPointAddTweakResult {
68
41
  parity: 1 | 0;
69
42
  xOnlyPubkey: Uint8Array;
70
43
  }
44
+ /** @ignore */
71
45
  export interface TinySecp256k1Interface {
72
46
  isPoint(p: Uint8Array): boolean;
73
47
  pointCompress(p: Uint8Array, compressed?: boolean): Uint8Array;
@@ -82,52 +56,93 @@ export interface TinySecp256k1Interface {
82
56
  xOnlyPointAddTweak(p: Uint8Array, tweak: Uint8Array): XOnlyPointAddTweakResult | null;
83
57
  privateNegate(d: Uint8Array): Uint8Array;
84
58
  }
59
+ export type Expansion = {
60
+ /**
61
+ * The corresponding [bitcoinjs-lib Payment](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/payments/index.ts) for the provided expression, if applicable.
62
+ */
63
+ payment?: Payment;
64
+ /**
65
+ * The expanded descriptor expression.
66
+ */
67
+ expandedExpression?: string;
68
+ /**
69
+ * The extracted miniscript from the expression, if any.
70
+ */
71
+ miniscript?: string;
72
+ /**
73
+ * A map of key expressions in the descriptor to their corresponding expanded keys.
74
+ */
75
+ expansionMap?: ExpansionMap;
76
+ /**
77
+ * A boolean indicating whether the descriptor represents a SegWit script.
78
+ */
79
+ isSegwit?: boolean;
80
+ /**
81
+ * The expanded miniscript, if any.
82
+ */
83
+ expandedMiniscript?: string;
84
+ /**
85
+ * The redeem script for the descriptor, if applicable.
86
+ */
87
+ redeemScript?: Buffer;
88
+ /**
89
+ * The witness script for the descriptor, if applicable.
90
+ */
91
+ witnessScript?: Buffer;
92
+ /**
93
+ * Whether this expression represents a ranged-descriptor.
94
+ */
95
+ isRanged: boolean;
96
+ /**
97
+ * This is the preferred or authoritative representation of the descriptor expression.
98
+ */
99
+ canonicalExpression: string;
100
+ };
85
101
  /**
86
- * DescriptorInfo
87
- * What defines a Descriptor. This is the type needed in the constructor.
88
- * @alias DescriptorInfo
89
- * @memberof Descriptor
102
+ * The {@link DescriptorsFactory | `DescriptorsFactory`} function creates and returns an implementation of the `Expand` interface.
103
+ * This returned implementation is tailored for the provided `TinySecp256k1Interface`.
90
104
  */
91
- export type DescriptorInfo = {
92
- expression: string;
93
- index?: number;
94
- checksumRequired?: boolean;
95
- allowMiniscriptInP2SH?: boolean;
96
- network?: Network;
97
- preimages?: Preimage[];
98
- signersPubKeys?: Buffer[];
99
- };
100
- export interface DescriptorInterface {
101
- getPayment(): Payment;
102
- getAddress(): string;
103
- getScriptPubKey(): Buffer;
104
- getScriptSatisfaction(signatures: PartialSig[]): Buffer;
105
- getSequence(): number | undefined;
106
- getLockTime(): number | undefined;
107
- getWitnessScript(): Buffer | undefined;
108
- getRedeemScript(): Buffer | undefined;
109
- getNetwork(): Network;
110
- isSegwit(): boolean | undefined;
111
- updatePsbt({ psbt, vout, txHex, txId, value }: {
112
- psbt: Psbt;
113
- vout: number;
114
- txHex?: string;
115
- txId?: string;
116
- value?: number;
117
- }): number;
118
- finalizePsbtInput({ index, psbt, validate }: {
119
- index: number;
120
- psbt: Psbt;
121
- validate?: boolean | undefined;
122
- }): void;
123
- expand(): {
124
- expandedExpression?: string;
125
- miniscript?: string;
126
- expandedMiniscript?: string;
127
- expansionMap?: ExpansionMap;
128
- };
105
+ export interface Expand {
106
+ (params: {
107
+ /**
108
+ * The descriptor expression to be expanded.
109
+ */
110
+ expression: string;
111
+ /**
112
+ * The descriptor index, if ranged.
113
+ */
114
+ index?: number;
115
+ /**
116
+ * A flag indicating whether the descriptor is required to include a checksum.
117
+ * @defaultValue false
118
+ */
119
+ checksumRequired?: boolean;
120
+ /**
121
+ * The Bitcoin network to use.
122
+ * @defaultValue `networks.bitcoin`
123
+ */
124
+ network?: Network;
125
+ /**
126
+ * Flag to allow miniscript in P2SH.
127
+ * @defaultValue false
128
+ */
129
+ allowMiniscriptInP2SH?: boolean;
130
+ }): Expansion;
129
131
  }
130
- export interface DescriptorInterfaceConstructor {
131
- new (args: DescriptorInfo): DescriptorInterface;
132
+ /**
133
+ * The {@link DescriptorsFactory | `DescriptorsFactory`} function creates and returns an implementation of the `ParseKeyExpression` interface.
134
+ * This returned implementation is tailored for the provided `TinySecp256k1Interface`.
135
+ */
136
+ export interface ParseKeyExpression {
137
+ (params: {
138
+ keyExpression: string;
139
+ /**
140
+ * Indicates if this is a SegWit key expression. When set, further checks
141
+ * ensure the public key (if present in the expression) is compressed
142
+ * (33 bytes).
143
+ */
144
+ isSegwit?: boolean;
145
+ network?: Network;
146
+ }): KeyInfo;
132
147
  }
133
148
  export {};
package/package.json CHANGED
@@ -1,39 +1,10 @@
1
1
  {
2
2
  "name": "@bitcoinerlab/descriptors",
3
- "homepage": "https://github.com/bitcoinerlab/descriptors",
4
- "version": "1.0.1",
5
3
  "description": "This library parses and creates Bitcoin Miniscript Descriptors and generates Partially Signed Bitcoin Transactions (PSBTs). It provides PSBT finalizers and signers for single-signature, BIP32 and Hardware Wallets.",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "scripts": {
9
- "build": "npx tsc",
10
- "prepublishOnly": "npm run build && npm test && echo \"\\n\\n\" && npm run test:integration:ledger",
11
- "docs": "jsdoc -c jsdoc.json",
12
- "regtest-docker": "docker ps | grep bitcoinerlab/tester > /dev/null || (docker pull bitcoinerlab/tester && docker run -d -p 8080:8080 -p 60401:60401 -p 3002:3002 bitcoinerlab/tester && sleep 5)",
13
- "test:integration:soft": "npm run regtest-docker && npx ts-node test/integration/standardOutputs.ts && echo \"\\n\\n\" && npx ts-node test/integration/miniscript.ts",
14
- "test:integration:ledger": "npm run regtest-docker && npx ts-node test/integration/ledger.ts",
15
- "test:unit": "npm run build && node test/tools/generateBitcoinCoreFixtures.js && jest",
16
- "test": "npm run lint && npm run lint:test && npm run test:unit && npm run test:integration:soft",
17
- "lint": "eslint --ignore-path .gitignore --ext .js,.ts src/",
18
- "lint:test": "eslint --ignore-path .gitignore --ext .js,.ts test/"
19
- },
20
- "COMMENT_babel": "Babel plugins are are only needed for the jest testing environment. Jest needs to use commonjs. Also, jest cannot handle ESM converted code, since it uses 'import.meta.url'. See src/bindings.js. babel-plugin-transform-import-meta fixes it.",
21
- "babel": {
22
- "env": {
23
- "test": {
24
- "plugins": [
25
- "@babel/plugin-transform-modules-commonjs",
26
- "babel-plugin-transform-import-meta"
27
- ]
28
- }
29
- }
30
- },
31
- "jest": {
32
- "testPathIgnorePatterns": [
33
- "example/",
34
- "dist/"
35
- ]
36
- },
4
+ "homepage": "https://github.com/bitcoinerlab/descriptors",
5
+ "version": "1.1.1",
6
+ "author": "Jose-Luis Landabaso",
7
+ "license": "MIT",
37
8
  "repository": {
38
9
  "type": "git",
39
10
  "url": "git+https://github.com/bitcoinerlab/descriptors.git"
@@ -44,11 +15,34 @@
44
15
  "bitcoinjs",
45
16
  "miniscript"
46
17
  ],
47
- "author": "Jose-Luis Landabaso",
48
- "license": "MIT",
49
18
  "bugs": {
50
19
  "url": "https://github.com/bitcoinerlab/descriptors/issues"
51
20
  },
21
+ "main": "dist/index.js",
22
+ "types": "dist/index.d.ts",
23
+ "prettier": "@bitcoinerlab/configs/prettierConfig.json",
24
+ "eslintConfig": {
25
+ "extends": "./node_modules/@bitcoinerlab/configs/eslintConfig"
26
+ },
27
+ "jest": {
28
+ "preset": "@bitcoinerlab/configs"
29
+ },
30
+ "scripts": {
31
+ "webdocs": "typedoc --options ./node_modules/@bitcoinerlab/configs/webtypedoc.json",
32
+ "docs": "typedoc --options ./node_modules/@bitcoinerlab/configs/typedoc.json",
33
+ "build:src": "tsc --project ./node_modules/@bitcoinerlab/configs/tsconfig.src.json",
34
+ "build:fixtures": "node test/tools/generateBitcoinCoreFixtures.js -i test/fixtures/descriptor_tests.cpp | npx prettier --parser typescript > test/fixtures/bitcoinCore.ts",
35
+ "build:test": "npm run build:fixtures && tsc --project ./node_modules/@bitcoinerlab/configs/tsconfig.test.json",
36
+ "build": "npm run build:src && npm run build:test",
37
+ "lint": "eslint --ignore-path .gitignore --ext .ts src/ test/",
38
+ "ensureTester": "./node_modules/@bitcoinerlab/configs/scripts/ensureTester.sh",
39
+ "test:integration:soft": "npm run ensureTester && node test/integration/standardOutputs.js && echo \"\\n\\n\" && node test/integration/miniscript.js",
40
+ "test:integration:ledger": "npm run ensureTester && node test/integration/ledger.js",
41
+ "test:unit": "jest",
42
+ "test": "npm run lint && npm run build && npm run test:unit && npm run test:integration:soft",
43
+ "testledger": "npm run lint && npm run build && npm run test:integration:ledger",
44
+ "prepublishOnly": "npm run test && echo \"\\n\\n\" && npm run test:integration:ledger"
45
+ },
52
46
  "files": [
53
47
  "dist"
54
48
  ],
@@ -61,27 +55,14 @@
61
55
  }
62
56
  },
63
57
  "devDependencies": {
64
- "@babel/plugin-transform-modules-commonjs": "^7.20.11",
58
+ "@bitcoinerlab/configs": "github:bitcoinerlab/configs",
65
59
  "@ledgerhq/hw-transport-node-hid": "^6.27.12",
66
- "@typescript-eslint/eslint-plugin": "^5.60.1",
67
- "@typescript-eslint/parser": "^5.60.1",
68
- "babel-plugin-transform-import-meta": "^2.2.0",
69
- "better-docs": "^2.7.2",
70
60
  "bip39": "^3.0.4",
71
61
  "bip65": "^1.0.3",
72
62
  "bip68": "^1.0.4",
73
- "eslint-config-prettier": "^8.6.0",
74
- "eslint-plugin-jest": "^27.2.1",
75
- "eslint-plugin-prettier": "^4.2.1",
76
- "fs": "^0.0.1-security",
77
- "jest": "^29.4.3",
78
- "jsdoc": "^3.6.11",
79
63
  "ledger-bitcoin": "^0.2.2",
80
- "path": "^0.12.7",
81
- "prettier": "^2.8.8",
82
64
  "regtest-client": "^0.2.0",
83
- "ts-node-dev": "^2.0.0",
84
- "typescript": "5.0"
65
+ "yargs": "^17.7.2"
85
66
  },
86
67
  "dependencies": {
87
68
  "@bitcoinerlab/miniscript": "^1.2.1",