@bitcoinerlab/descriptors 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -60,49 +60,72 @@ function countNonPushOnlyOPs(script) {
60
60
  /*
61
61
  * Returns a bare descriptor without checksum and particularized for a certain
62
62
  * index (if desc was a range descriptor)
63
+ * @hidden
63
64
  */
64
- function evaluate({ expression, checksumRequired, index }) {
65
- const mChecksum = expression.match(String.raw `(${RE.reChecksum})$`);
65
+ function evaluate({ descriptor, checksumRequired, index }) {
66
+ if (!descriptor)
67
+ throw new Error('You must provide a descriptor.');
68
+ const mChecksum = descriptor.match(String.raw `(${RE.reChecksum})$`);
66
69
  if (mChecksum === null && checksumRequired === true)
67
- throw new Error(`Error: descriptor ${expression} has not checksum`);
68
- //evaluatedExpression: a bare desc without checksum and particularized for a certain
70
+ throw new Error(`Error: descriptor ${descriptor} has not checksum`);
71
+ //evaluatedDescriptor: a bare desc without checksum and particularized for a certain
69
72
  //index (if desc was a range descriptor)
70
- let evaluatedExpression = expression;
73
+ let evaluatedDescriptor = descriptor;
71
74
  if (mChecksum !== null) {
72
75
  const checksum = mChecksum[0].substring(1); //remove the leading #
73
- evaluatedExpression = expression.substring(0, expression.length - mChecksum[0].length);
74
- if (checksum !== (0, checksum_1.DescriptorChecksum)(evaluatedExpression)) {
75
- throw new Error(`Error: invalid descriptor checksum for ${expression}`);
76
+ evaluatedDescriptor = descriptor.substring(0, descriptor.length - mChecksum[0].length);
77
+ if (checksum !== (0, checksum_1.DescriptorChecksum)(evaluatedDescriptor)) {
78
+ throw new Error(`Error: invalid descriptor checksum for ${descriptor}`);
76
79
  }
77
80
  }
78
81
  if (index !== undefined) {
79
- const mWildcard = evaluatedExpression.match(/\*/g);
82
+ const mWildcard = evaluatedDescriptor.match(/\*/g);
80
83
  if (mWildcard && mWildcard.length > 0) {
81
84
  //From https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md
82
85
  //To prevent a combinatorial explosion of the search space, if more than
83
86
  //one of the multi() key arguments is a BIP32 wildcard path ending in /* or
84
- //*', the multi() expression only matches multisig scripts with the ith
87
+ //*', the multi() descriptor only matches multisig scripts with the ith
85
88
  //child key from each wildcard path in lockstep, rather than scripts with
86
89
  //any combination of child keys from each wildcard path.
87
90
  //We extend this reasoning for musig for all cases
88
- evaluatedExpression = evaluatedExpression.replaceAll('*', index.toString());
91
+ evaluatedDescriptor = evaluatedDescriptor.replaceAll('*', index.toString());
89
92
  }
90
93
  else
91
- throw new Error(`Error: index passed for non-ranged descriptor: ${expression}`);
94
+ throw new Error(`Error: index passed for non-ranged descriptor: ${descriptor}`);
92
95
  }
93
- return evaluatedExpression;
96
+ return evaluatedDescriptor;
94
97
  }
95
98
  /**
96
- * Builds the functions needed to operate with descriptors using an external elliptic curve (ecc) library.
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
+ * Constructs the necessary functions and classes for working with descriptors
100
+ * using an external elliptic curve (ecc) library.
101
+ *
102
+ * Notably, it returns the {@link _Internal_.Output | `Output`} class, which
103
+ * provides methods to create, sign, and finalize PSBTs based on descriptor
104
+ * expressions.
105
+ *
106
+ * While this Factory function includes the `Descriptor` class, note that
107
+ * this class was deprecated in v2.0 in favor of `Output`. For backward
108
+ * compatibility, the `Descriptor` class remains, but using `Output` is advised.
109
+ *
110
+ * The Factory also returns utility methods like `expand` (detailed below)
111
+ * and `parseKeyExpression` (see {@link ParseKeyExpression}).
112
+ *
113
+ * Additionally, for convenience, the function returns `BIP32` and `ECPair`.
114
+ * These are {@link https://github.com/bitcoinjs bitcoinjs-lib} classes designed
115
+ * for managing {@link https://github.com/bitcoinjs/bip32 | `BIP32`} keys and
116
+ * public/private key pairs:
117
+ * {@link https://github.com/bitcoinjs/ecpair | `ECPair`}, respectively.
118
+ *
119
+ * @param {Object} ecc - An object with elliptic curve operations, such as
120
+ * [tiny-secp256k1](https://github.com/bitcoinjs/tiny-secp256k1) or
121
+ * [@bitcoinerlab/secp256k1](https://github.com/bitcoinerlab/secp256k1).
99
122
  */
100
123
  function DescriptorsFactory(ecc) {
101
- 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;
124
+ var _Output_instances, _Output_payment, _Output_preimages, _Output_signersPubKeys, _Output_miniscript, _Output_witnessScript, _Output_redeemScript, _Output_isSegwit, _Output_expandedExpression, _Output_expandedMiniscript, _Output_expansionMap, _Output_network, _Output_getTimeConstraints, _Output_assertPsbtInput;
102
125
  const BIP32 = (0, bip32_1.BIP32Factory)(ecc);
103
126
  const ECPair = (0, ecpair_1.ECPairFactory)(ecc);
104
127
  const signatureValidator = (pubkey, msghash, signature) => ECPair.fromPublicKey(pubkey).verify(msghash, signature);
105
- /*
128
+ /**
106
129
  * Takes a string key expression (xpub, xprv, pubkey or wif) and parses it
107
130
  */
108
131
  const parseKeyExpression = ({ keyExpression, isSegwit, network = bitcoinjs_lib_1.networks.bitcoin }) => {
@@ -115,32 +138,16 @@ function DescriptorsFactory(ecc) {
115
138
  });
116
139
  };
117
140
  /**
118
- * Takes a descriptor (expression) and expands it to its corresponding Bitcoin script and other relevant details.
119
- *
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
- * @throws {Error} Throws an error if the descriptor cannot be parsed or does not conform to the expected format.
141
+ * @hidden
142
+ * To be removed in v3.0 and replaced by the version with the signature that
143
+ * does not accept descriptors
142
144
  */
143
- const expand = ({ expression, index, checksumRequired = false, network = bitcoinjs_lib_1.networks.bitcoin, allowMiniscriptInP2SH = false }) => {
145
+ function expand({ descriptor, expression, index, checksumRequired = false, network = bitcoinjs_lib_1.networks.bitcoin, allowMiniscriptInP2SH = false }) {
146
+ if (descriptor && expression)
147
+ throw new Error(`expression param has been deprecated`);
148
+ descriptor = descriptor || expression;
149
+ if (!descriptor)
150
+ throw new Error(`descriptor not provided`);
144
151
  let expandedExpression;
145
152
  let miniscript;
146
153
  let expansionMap;
@@ -149,14 +156,14 @@ function DescriptorsFactory(ecc) {
149
156
  let payment;
150
157
  let witnessScript;
151
158
  let redeemScript;
152
- const isRanged = expression.indexOf('*') !== -1;
159
+ const isRanged = descriptor.indexOf('*') !== -1;
153
160
  if (index !== undefined)
154
161
  if (!Number.isInteger(index) || index < 0)
155
162
  throw new Error(`Error: invalid index ${index}`);
156
163
  //Verify and remove checksum (if exists) and
157
164
  //particularize range descriptor for index (if desc is range descriptor)
158
165
  const canonicalExpression = evaluate({
159
- expression,
166
+ descriptor,
160
167
  ...(index !== undefined ? { index } : {}),
161
168
  checksumRequired
162
169
  });
@@ -167,7 +174,7 @@ function DescriptorsFactory(ecc) {
167
174
  throw new Error(`Error: addr() cannot be ranged`);
168
175
  const matchedAddress = canonicalExpression.match(RE.reAddrAnchored)?.[1]; //[1]-> whatever is found addr(->HERE<-)
169
176
  if (!matchedAddress)
170
- throw new Error(`Error: could not get an address in ${expression}`);
177
+ throw new Error(`Error: could not get an address in ${descriptor}`);
171
178
  let output;
172
179
  try {
173
180
  output = bitcoinjs_lib_1.address.toOutputScript(matchedAddress, network);
@@ -206,7 +213,7 @@ function DescriptorsFactory(ecc) {
206
213
  if (!keyExpression)
207
214
  throw new Error(`Error: keyExpression could not me extracted`);
208
215
  if (canonicalExpression !== `pk(${keyExpression})`)
209
- throw new Error(`Error: invalid expression ${expression}`);
216
+ throw new Error(`Error: invalid expression ${descriptor}`);
210
217
  expandedExpression = 'pk(@0)';
211
218
  const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
212
219
  expansionMap = { '@0': pKE };
@@ -214,7 +221,7 @@ function DescriptorsFactory(ecc) {
214
221
  const pubkey = pKE.pubkey;
215
222
  //Note there exists no address for p2pk, but we can still use the script
216
223
  if (!pubkey)
217
- throw new Error(`Error: could not extract a pubkey from ${expression}`);
224
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
218
225
  payment = p2pk({ pubkey, network });
219
226
  }
220
227
  }
@@ -225,14 +232,14 @@ function DescriptorsFactory(ecc) {
225
232
  if (!keyExpression)
226
233
  throw new Error(`Error: keyExpression could not me extracted`);
227
234
  if (canonicalExpression !== `pkh(${keyExpression})`)
228
- throw new Error(`Error: invalid expression ${expression}`);
235
+ throw new Error(`Error: invalid expression ${descriptor}`);
229
236
  expandedExpression = 'pkh(@0)';
230
237
  const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
231
238
  expansionMap = { '@0': pKE };
232
239
  if (!isCanonicalRanged) {
233
240
  const pubkey = pKE.pubkey;
234
241
  if (!pubkey)
235
- throw new Error(`Error: could not extract a pubkey from ${expression}`);
242
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
236
243
  payment = p2pkh({ pubkey, network });
237
244
  }
238
245
  }
@@ -243,18 +250,18 @@ function DescriptorsFactory(ecc) {
243
250
  if (!keyExpression)
244
251
  throw new Error(`Error: keyExpression could not me extracted`);
245
252
  if (canonicalExpression !== `sh(wpkh(${keyExpression}))`)
246
- throw new Error(`Error: invalid expression ${expression}`);
253
+ throw new Error(`Error: invalid expression ${descriptor}`);
247
254
  expandedExpression = 'sh(wpkh(@0))';
248
255
  const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
249
256
  expansionMap = { '@0': pKE };
250
257
  if (!isCanonicalRanged) {
251
258
  const pubkey = pKE.pubkey;
252
259
  if (!pubkey)
253
- throw new Error(`Error: could not extract a pubkey from ${expression}`);
260
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
254
261
  payment = p2sh({ redeem: p2wpkh({ pubkey, network }), network });
255
262
  redeemScript = payment.redeem?.output;
256
263
  if (!redeemScript)
257
- throw new Error(`Error: could not calculate redeemScript for ${expression}`);
264
+ throw new Error(`Error: could not calculate redeemScript for ${descriptor}`);
258
265
  }
259
266
  }
260
267
  //wpkh(KEY) - native segwit
@@ -264,14 +271,14 @@ function DescriptorsFactory(ecc) {
264
271
  if (!keyExpression)
265
272
  throw new Error(`Error: keyExpression could not me extracted`);
266
273
  if (canonicalExpression !== `wpkh(${keyExpression})`)
267
- throw new Error(`Error: invalid expression ${expression}`);
274
+ throw new Error(`Error: invalid expression ${descriptor}`);
268
275
  expandedExpression = 'wpkh(@0)';
269
276
  const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
270
277
  expansionMap = { '@0': pKE };
271
278
  if (!isCanonicalRanged) {
272
279
  const pubkey = pKE.pubkey;
273
280
  if (!pubkey)
274
- throw new Error(`Error: could not extract a pubkey from ${expression}`);
281
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
275
282
  payment = p2wpkh({ pubkey, network });
276
283
  }
277
284
  }
@@ -280,7 +287,7 @@ function DescriptorsFactory(ecc) {
280
287
  isSegwit = true;
281
288
  miniscript = canonicalExpression.match(RE.reShWshMiniscriptAnchored)?.[1]; //[1]-> whatever is found sh(wsh(->HERE<-))
282
289
  if (!miniscript)
283
- throw new Error(`Error: could not get miniscript in ${expression}`);
290
+ throw new Error(`Error: could not get miniscript in ${descriptor}`);
284
291
  ({ expandedMiniscript, expansionMap } = expandMiniscript({
285
292
  miniscript,
286
293
  isSegwit,
@@ -303,7 +310,7 @@ function DescriptorsFactory(ecc) {
303
310
  });
304
311
  redeemScript = payment.redeem?.output;
305
312
  if (!redeemScript)
306
- throw new Error(`Error: could not calculate redeemScript for ${expression}`);
313
+ throw new Error(`Error: could not calculate redeemScript for ${descriptor}`);
307
314
  }
308
315
  }
309
316
  //sh(miniscript)
@@ -313,7 +320,7 @@ function DescriptorsFactory(ecc) {
313
320
  isSegwit = false;
314
321
  miniscript = canonicalExpression.match(RE.reShMiniscriptAnchored)?.[1]; //[1]-> whatever is found sh(->HERE<-)
315
322
  if (!miniscript)
316
- throw new Error(`Error: could not get miniscript in ${expression}`);
323
+ throw new Error(`Error: could not get miniscript in ${descriptor}`);
317
324
  if (allowMiniscriptInP2SH === false &&
318
325
  //These top-level expressions within sh are allowed within sh.
319
326
  //They can be parsed with miniscript2Script, but first we must make sure
@@ -345,7 +352,7 @@ function DescriptorsFactory(ecc) {
345
352
  isSegwit = true;
346
353
  miniscript = canonicalExpression.match(RE.reWshMiniscriptAnchored)?.[1]; //[1]-> whatever is found wsh(->HERE<-)
347
354
  if (!miniscript)
348
- throw new Error(`Error: could not get miniscript in ${expression}`);
355
+ throw new Error(`Error: could not get miniscript in ${descriptor}`);
349
356
  ({ expandedMiniscript, expansionMap } = expandMiniscript({
350
357
  miniscript,
351
358
  isSegwit,
@@ -366,7 +373,7 @@ function DescriptorsFactory(ecc) {
366
373
  }
367
374
  }
368
375
  else {
369
- throw new Error(`Error: Could not parse descriptor ${expression}`);
376
+ throw new Error(`Error: Could not parse descriptor ${descriptor}`);
370
377
  }
371
378
  return {
372
379
  ...(payment !== undefined ? { payment } : {}),
@@ -380,7 +387,7 @@ function DescriptorsFactory(ecc) {
380
387
  isRanged,
381
388
  canonicalExpression
382
389
  };
383
- };
390
+ }
384
391
  /**
385
392
  * Expand a miniscript to a generalized form using variables instead of key
386
393
  * expressions. Variables will be of this form: @0, @1, ...
@@ -397,40 +404,38 @@ function DescriptorsFactory(ecc) {
397
404
  ECPair
398
405
  });
399
406
  }
400
- class Descriptor {
407
+ /**
408
+ * The `Output` class is the central component for managing descriptors.
409
+ * It facilitates the creation of outputs to receive funds and enables the
410
+ * signing and finalization of PSBTs (Partially Signed Bitcoin Transactions)
411
+ * for spending UTXOs (Unspent Transaction Outputs).
412
+ */
413
+ class Output {
401
414
  /**
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
- *
415
+ * @param options
411
416
  * @throws {Error} - when descriptor is invalid
412
417
  */
413
- constructor({ expression, index, checksumRequired = false, allowMiniscriptInP2SH = false, network = bitcoinjs_lib_1.networks.bitcoin, preimages = [], signersPubKeys }) {
414
- _Descriptor_instances.add(this);
415
- _Descriptor_payment.set(this, void 0);
416
- _Descriptor_preimages.set(this, []);
417
- _Descriptor_signersPubKeys.set(this, void 0);
418
- _Descriptor_miniscript.set(this, void 0);
419
- _Descriptor_witnessScript.set(this, void 0);
420
- _Descriptor_redeemScript.set(this, void 0);
418
+ constructor({ descriptor, index, checksumRequired = false, allowMiniscriptInP2SH = false, network = bitcoinjs_lib_1.networks.bitcoin, preimages = [], signersPubKeys }) {
419
+ _Output_instances.add(this);
420
+ _Output_payment.set(this, void 0);
421
+ _Output_preimages.set(this, []);
422
+ _Output_signersPubKeys.set(this, void 0);
423
+ _Output_miniscript.set(this, void 0);
424
+ _Output_witnessScript.set(this, void 0);
425
+ _Output_redeemScript.set(this, void 0);
421
426
  //isSegwit true if witnesses are needed to the spend coins sent to this descriptor.
422
427
  //may be unset because we may get addr(P2SH) which we don't know if they have segwit.
423
- _Descriptor_isSegwit.set(this, void 0);
424
- _Descriptor_expandedExpression.set(this, void 0);
425
- _Descriptor_expandedMiniscript.set(this, void 0);
426
- _Descriptor_expansionMap.set(this, void 0);
427
- _Descriptor_network.set(this, void 0);
428
- __classPrivateFieldSet(this, _Descriptor_network, network, "f");
429
- __classPrivateFieldSet(this, _Descriptor_preimages, preimages, "f");
430
- if (typeof expression !== 'string')
428
+ _Output_isSegwit.set(this, void 0);
429
+ _Output_expandedExpression.set(this, void 0);
430
+ _Output_expandedMiniscript.set(this, void 0);
431
+ _Output_expansionMap.set(this, void 0);
432
+ _Output_network.set(this, void 0);
433
+ __classPrivateFieldSet(this, _Output_network, network, "f");
434
+ __classPrivateFieldSet(this, _Output_preimages, preimages, "f");
435
+ if (typeof descriptor !== 'string')
431
436
  throw new Error(`Error: invalid descriptor type`);
432
437
  const expandedResult = expand({
433
- expression,
438
+ descriptor,
434
439
  ...(index !== undefined ? { index } : {}),
435
440
  checksumRequired,
436
441
  network,
@@ -439,68 +444,89 @@ function DescriptorsFactory(ecc) {
439
444
  if (expandedResult.isRanged && index === undefined)
440
445
  throw new Error(`Error: index was not provided for ranged descriptor`);
441
446
  if (!expandedResult.payment)
442
- throw new Error(`Error: could not extract a payment from ${expression}`);
443
- __classPrivateFieldSet(this, _Descriptor_payment, expandedResult.payment, "f");
447
+ throw new Error(`Error: could not extract a payment from ${descriptor}`);
448
+ __classPrivateFieldSet(this, _Output_payment, expandedResult.payment, "f");
444
449
  if (expandedResult.expandedExpression !== undefined)
445
- __classPrivateFieldSet(this, _Descriptor_expandedExpression, expandedResult.expandedExpression, "f");
450
+ __classPrivateFieldSet(this, _Output_expandedExpression, expandedResult.expandedExpression, "f");
446
451
  if (expandedResult.miniscript !== undefined)
447
- __classPrivateFieldSet(this, _Descriptor_miniscript, expandedResult.miniscript, "f");
452
+ __classPrivateFieldSet(this, _Output_miniscript, expandedResult.miniscript, "f");
448
453
  if (expandedResult.expansionMap !== undefined)
449
- __classPrivateFieldSet(this, _Descriptor_expansionMap, expandedResult.expansionMap, "f");
454
+ __classPrivateFieldSet(this, _Output_expansionMap, expandedResult.expansionMap, "f");
450
455
  if (expandedResult.isSegwit !== undefined)
451
- __classPrivateFieldSet(this, _Descriptor_isSegwit, expandedResult.isSegwit, "f");
456
+ __classPrivateFieldSet(this, _Output_isSegwit, expandedResult.isSegwit, "f");
452
457
  if (expandedResult.expandedMiniscript !== undefined)
453
- __classPrivateFieldSet(this, _Descriptor_expandedMiniscript, expandedResult.expandedMiniscript, "f");
458
+ __classPrivateFieldSet(this, _Output_expandedMiniscript, expandedResult.expandedMiniscript, "f");
454
459
  if (expandedResult.redeemScript !== undefined)
455
- __classPrivateFieldSet(this, _Descriptor_redeemScript, expandedResult.redeemScript, "f");
460
+ __classPrivateFieldSet(this, _Output_redeemScript, expandedResult.redeemScript, "f");
456
461
  if (expandedResult.witnessScript !== undefined)
457
- __classPrivateFieldSet(this, _Descriptor_witnessScript, expandedResult.witnessScript, "f");
462
+ __classPrivateFieldSet(this, _Output_witnessScript, expandedResult.witnessScript, "f");
458
463
  if (signersPubKeys) {
459
- __classPrivateFieldSet(this, _Descriptor_signersPubKeys, signersPubKeys, "f");
464
+ __classPrivateFieldSet(this, _Output_signersPubKeys, signersPubKeys, "f");
460
465
  }
461
466
  else {
462
- if (__classPrivateFieldGet(this, _Descriptor_expansionMap, "f")) {
463
- __classPrivateFieldSet(this, _Descriptor_signersPubKeys, Object.values(__classPrivateFieldGet(this, _Descriptor_expansionMap, "f")).map(keyInfo => {
467
+ if (__classPrivateFieldGet(this, _Output_expansionMap, "f")) {
468
+ __classPrivateFieldSet(this, _Output_signersPubKeys, Object.values(__classPrivateFieldGet(this, _Output_expansionMap, "f")).map(keyInfo => {
464
469
  const pubkey = keyInfo.pubkey;
465
470
  if (!pubkey)
466
- throw new Error(`Error: could not extract a pubkey from ${expression}`);
471
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
467
472
  return pubkey;
468
473
  }), "f");
469
474
  }
470
475
  else {
471
476
  //We should only miss expansionMap in addr() expressions:
472
477
  if (!expandedResult.canonicalExpression.match(RE.reAddrAnchored)) {
473
- throw new Error(`Error: expansionMap not available for expression ${expression} that is not an address`);
478
+ throw new Error(`Error: expansionMap not available for expression ${descriptor} that is not an address`);
474
479
  }
475
- __classPrivateFieldSet(this, _Descriptor_signersPubKeys, [this.getScriptPubKey()], "f");
480
+ __classPrivateFieldSet(this, _Output_signersPubKeys, [this.getScriptPubKey()], "f");
476
481
  }
477
482
  }
478
483
  }
484
+ /**
485
+ * Creates and returns an instance of bitcoinjs-lib
486
+ * [`Payment`](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/payments/index.ts)'s interface with the `scriptPubKey` of this `Output`.
487
+ */
479
488
  getPayment() {
480
- return __classPrivateFieldGet(this, _Descriptor_payment, "f");
489
+ return __classPrivateFieldGet(this, _Output_payment, "f");
481
490
  }
482
491
  /**
483
- * Returns the Bitcoin Address
492
+ * Returns the Bitcoin Address of this `Output`.
484
493
  */
485
494
  getAddress() {
486
- if (!__classPrivateFieldGet(this, _Descriptor_payment, "f").address)
495
+ if (!__classPrivateFieldGet(this, _Output_payment, "f").address)
487
496
  throw new Error(`Error: could extract an address from the payment`);
488
- return __classPrivateFieldGet(this, _Descriptor_payment, "f").address;
497
+ return __classPrivateFieldGet(this, _Output_payment, "f").address;
489
498
  }
499
+ /**
500
+ * Returns this `Output`'s scriptPubKey.
501
+ */
490
502
  getScriptPubKey() {
491
- if (!__classPrivateFieldGet(this, _Descriptor_payment, "f").output)
503
+ if (!__classPrivateFieldGet(this, _Output_payment, "f").output)
492
504
  throw new Error(`Error: could extract output.script from the payment`);
493
- return __classPrivateFieldGet(this, _Descriptor_payment, "f").output;
505
+ return __classPrivateFieldGet(this, _Output_payment, "f").output;
494
506
  }
495
507
  /**
496
- * Returns the compiled script satisfaction
497
- * @param {PartialSig[]} signatures An array of signatures using this format: `interface PartialSig { pubkey: Buffer; signature: Buffer; }`
498
- * @returns {Buffer}
508
+ * Returns the compiled Script Satisfaction if this `Output` was created
509
+ * using a miniscript-based descriptor.
510
+ *
511
+ * The Satisfaction is the unlocking script that fulfills
512
+ * (satisfies) this `Output` and it is derived using the Safisfier algorithm
513
+ * [described here](https://bitcoin.sipa.be/miniscript/).
514
+ *
515
+ * Important: As mentioned above, note that this function only applies to
516
+ * miniscript descriptors.
499
517
  */
500
- getScriptSatisfaction(signatures) {
501
- const miniscript = __classPrivateFieldGet(this, _Descriptor_miniscript, "f");
502
- const expandedMiniscript = __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f");
503
- const expansionMap = __classPrivateFieldGet(this, _Descriptor_expansionMap, "f");
518
+ getScriptSatisfaction(
519
+ /**
520
+ * An array with all the signatures needed to
521
+ * build the Satisfaction of this miniscript-based `Output`.
522
+ *
523
+ * `signatures` must be passed using this format (pairs of `pubKey/signature`):
524
+ * `interface PartialSig { pubkey: Buffer; signature: Buffer; }`
525
+ */
526
+ signatures) {
527
+ const miniscript = __classPrivateFieldGet(this, _Output_miniscript, "f");
528
+ const expandedMiniscript = __classPrivateFieldGet(this, _Output_expandedMiniscript, "f");
529
+ const expansionMap = __classPrivateFieldGet(this, _Output_expansionMap, "f");
504
530
  if (miniscript === undefined ||
505
531
  expandedMiniscript === undefined ||
506
532
  expansionMap === undefined)
@@ -514,7 +540,7 @@ function DescriptorsFactory(ecc) {
514
540
  expandedMiniscript,
515
541
  expansionMap,
516
542
  signatures,
517
- preimages: __classPrivateFieldGet(this, _Descriptor_preimages, "f"),
543
+ preimages: __classPrivateFieldGet(this, _Output_preimages, "f"),
518
544
  //Here we pass the TimeConstraints obtained using signersPubKeys to
519
545
  //verify that the solutions found using the final signatures have not
520
546
  //changed
@@ -527,45 +553,76 @@ function DescriptorsFactory(ecc) {
527
553
  throw new Error(`Error: could not produce a valid satisfaction`);
528
554
  return scriptSatisfaction;
529
555
  }
556
+ /**
557
+ * Gets the nSequence required to fulfill this `Output`.
558
+ */
530
559
  getSequence() {
531
- return __classPrivateFieldGet(this, _Descriptor_instances, "m", _Descriptor_getTimeConstraints).call(this)?.nSequence;
560
+ return __classPrivateFieldGet(this, _Output_instances, "m", _Output_getTimeConstraints).call(this)?.nSequence;
532
561
  }
562
+ /**
563
+ * Gets the nLockTime required to fulfill this `Output`.
564
+ */
533
565
  getLockTime() {
534
- return __classPrivateFieldGet(this, _Descriptor_instances, "m", _Descriptor_getTimeConstraints).call(this)?.nLockTime;
566
+ return __classPrivateFieldGet(this, _Output_instances, "m", _Output_getTimeConstraints).call(this)?.nLockTime;
535
567
  }
568
+ /**
569
+ * Gets the witnessScript required to fulfill this `Output`. Only applies to
570
+ * Segwit outputs.
571
+ */
536
572
  getWitnessScript() {
537
- return __classPrivateFieldGet(this, _Descriptor_witnessScript, "f");
573
+ return __classPrivateFieldGet(this, _Output_witnessScript, "f");
538
574
  }
575
+ /**
576
+ * Gets the redeemScript required to fullfill this `Output`. Only applies to
577
+ * SH outputs: sh(wpkh), sh(wsh), sh(lockingScript).
578
+ */
539
579
  getRedeemScript() {
540
- return __classPrivateFieldGet(this, _Descriptor_redeemScript, "f");
580
+ return __classPrivateFieldGet(this, _Output_redeemScript, "f");
541
581
  }
582
+ /**
583
+ * Gets the bitcoinjs-lib [`network`](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/networks.ts) used to create this `Output`.
584
+ */
542
585
  getNetwork() {
543
- return __classPrivateFieldGet(this, _Descriptor_network, "f");
586
+ return __classPrivateFieldGet(this, _Output_network, "f");
544
587
  }
588
+ /**
589
+ * Whether this `Output` is Segwit.
590
+ */
545
591
  isSegwit() {
546
- return __classPrivateFieldGet(this, _Descriptor_isSegwit, "f");
592
+ return __classPrivateFieldGet(this, _Output_isSegwit, "f");
593
+ }
594
+ /** @deprecated - Use updatePsbtAsInput instead
595
+ * @hidden
596
+ */
597
+ updatePsbt(params) {
598
+ this.updatePsbtAsInput(params);
599
+ return params.psbt.data.inputs.length - 1;
547
600
  }
548
601
  /**
549
- * Updates a Psbt where the descriptor describes an utxo.
550
- * The txHex (nonWitnessUtxo) and vout of the utxo must be passed.
602
+ * Sets this output as an input of the provided `psbt` and updates the
603
+ * `psbt` locktime if required by the descriptor.
604
+ *
605
+ * `psbt` and `vout` are mandatory. Include `txHex` as well. The pair
606
+ * `vout` and `txHex` define the transaction and output number this instance
607
+ * pertains to.
608
+ *
609
+ * Though not advised, for Segwit inputs you can pass `txId` and `value`
610
+ * in lieu of `txHex`. If doing so, ensure `value` accuracy to avoid
611
+ * potential fee attacks -
612
+ * [See this issue](https://github.com/bitcoinjs/bitcoinjs-lib/issues/1625).
613
+ *
614
+ * Note: Hardware wallets need the [full `txHex` for Segwit](https://blog.trezor.io/details-of-firmware-updates-for-trezor-one-version-1-9-1-and-trezor-model-t-version-2-3-1-1eba8f60f2dd).
551
615
  *
552
- * updatePsbt adds an input to the psbt and updates the tx locktime if needed.
553
- * It also adds a new input to the Psbt based on txHex
554
- * It returns the number of the input that is added.
555
- * psbt and vout are mandatory. Also pass txHex.
616
+ * When unsure, always use `txHex`, and skip `txId` and `value` for safety.
556
617
  *
557
- * The following is not recommended but, alternatively, ONLY for Segwit inputs,
558
- * you can pass txId and value, instead of txHex.
559
- * If you do so, it is your responsibility to make sure that `value` is
560
- * correct to avoid possible fee vulnerability attacks:
561
- * https://github.com/bitcoinjs/bitcoinjs-lib/issues/1625
562
- * Note that HW wallets require the full txHex also for Segwit anyways:
563
- * https://blog.trezor.io/details-of-firmware-updates-for-trezor-one-version-1-9-1-and-trezor-model-t-version-2-3-1-1eba8f60f2dd
618
+ * @returns A finalizer function to be used after signing the `psbt`.
619
+ * This function ensures that this input is properly finalized.
620
+ * The finalizer has this signature:
621
+ *
622
+ * `( { psbt, validate = true } : { psbt: Psbt; validate: boolean | undefined } ) => void`
564
623
  *
565
- * In doubt, simply pass txHex (and you can skip passing txId and value) and
566
- * you shall be fine.
567
624
  */
568
- updatePsbt({ psbt, txHex, txId, value, vout //vector output index
625
+ updatePsbtAsInput({ psbt, txHex, txId, value, vout //vector output index
569
626
  }) {
570
627
  if (txHex === undefined) {
571
628
  console.warn(`Warning: missing txHex may allow fee attacks`);
@@ -575,7 +632,7 @@ function DescriptorsFactory(ecc) {
575
632
  //This should only happen when using addr() expressions
576
633
  throw new Error(`Error: could not determine whether this is a segwit descriptor`);
577
634
  }
578
- return (0, psbt_1.updatePsbt)({
635
+ const index = (0, psbt_1.updatePsbt)({
579
636
  psbt,
580
637
  vout,
581
638
  ...(txHex !== undefined ? { txHex } : {}),
@@ -583,13 +640,55 @@ function DescriptorsFactory(ecc) {
583
640
  ...(value !== undefined ? { value } : {}),
584
641
  sequence: this.getSequence(),
585
642
  locktime: this.getLockTime(),
586
- keysInfo: __classPrivateFieldGet(this, _Descriptor_expansionMap, "f") ? Object.values(__classPrivateFieldGet(this, _Descriptor_expansionMap, "f")) : [],
643
+ keysInfo: __classPrivateFieldGet(this, _Output_expansionMap, "f") ? Object.values(__classPrivateFieldGet(this, _Output_expansionMap, "f")) : [],
587
644
  scriptPubKey: this.getScriptPubKey(),
588
645
  isSegwit,
589
646
  witnessScript: this.getWitnessScript(),
590
647
  redeemScript: this.getRedeemScript()
591
648
  });
649
+ const finalizer = ({ psbt, validate = true }) => this.finalizePsbtInput({ index, psbt, validate });
650
+ return finalizer;
651
+ }
652
+ /**
653
+ * Adds this output as an output of the provided `psbt` with the given
654
+ * value.
655
+ *
656
+ * @param psbt - The Partially Signed Bitcoin Transaction.
657
+ * @param value - The value for the output in satoshis.
658
+ */
659
+ updatePsbtAsOutput({ psbt, value }) {
660
+ psbt.addOutput({ script: this.getScriptPubKey(), value });
592
661
  }
662
+ /**
663
+ * Finalizes a PSBT input by adding the necessary unlocking script that satisfies this `Output`'s
664
+ * spending conditions.
665
+ *
666
+ * 🔴 IMPORTANT 🔴
667
+ * It is STRONGLY RECOMMENDED to use the finalizer function returned by
668
+ * {@link _Internal_.Output.updatePsbtAsInput | `updatePsbtAsInput`} instead
669
+ * of calling this method directly.
670
+ * This approach eliminates the need to manage the `Output` instance and the
671
+ * input's index, simplifying the process.
672
+ *
673
+ * The `finalizePsbtInput` method completes a PSBT input by adding the
674
+ * unlocking script (`scriptWitness` or `scriptSig`) that satisfies
675
+ * this `Output`'s spending conditions. Bear in mind that both
676
+ * `scriptSig` and `scriptWitness` incorporate signatures. As such, you
677
+ * should complete all necessary signing operations before calling this
678
+ * method.
679
+ *
680
+ * For each unspent output from a previous transaction that you're
681
+ * referencing in a `psbt` as an input to be spent, apply this method as
682
+ * follows: `output.finalizePsbtInput({ index, psbt })`.
683
+ *
684
+ * It's essential to specify the exact position (or `index`) of the input in
685
+ * the `psbt` that references this unspent `Output`. This `index` should
686
+ * align with the value returned by the `updatePsbtAsInput` method.
687
+ * Note:
688
+ * The `index` corresponds to the position of the input in the `psbt`.
689
+ * To get this index, right after calling `updatePsbtAsInput()`, use:
690
+ * `index = psbt.data.inputs.length - 1`.
691
+ */
593
692
  finalizePsbtInput({ index, psbt, validate = true }) {
594
693
  if (validate &&
595
694
  !psbt.validateSignaturesOfInput(index, signatureValidator)) {
@@ -605,39 +704,43 @@ function DescriptorsFactory(ecc) {
605
704
  const signatures = psbt.data.inputs[index]?.partialSig;
606
705
  if (!signatures)
607
706
  throw new Error(`Error: cannot finalize without signatures`);
608
- __classPrivateFieldGet(this, _Descriptor_instances, "m", _Descriptor_assertPsbtInput).call(this, { index, psbt });
609
- if (!__classPrivateFieldGet(this, _Descriptor_miniscript, "f")) {
707
+ __classPrivateFieldGet(this, _Output_instances, "m", _Output_assertPsbtInput).call(this, { index, psbt });
708
+ if (!__classPrivateFieldGet(this, _Output_miniscript, "f")) {
610
709
  //Use standard finalizers
611
710
  psbt.finalizeInput(index);
612
711
  }
613
712
  else {
614
713
  const scriptSatisfaction = this.getScriptSatisfaction(signatures);
615
- psbt.finalizeInput(index, (0, psbt_1.finalScriptsFuncFactory)(scriptSatisfaction, __classPrivateFieldGet(this, _Descriptor_network, "f")));
714
+ psbt.finalizeInput(index, (0, psbt_1.finalScriptsFuncFactory)(scriptSatisfaction, __classPrivateFieldGet(this, _Output_network, "f")));
616
715
  }
617
716
  }
717
+ /**
718
+ * Decomposes the descriptor used to form this `Output` into its elemental
719
+ * parts. See {@link ExpansionMap ExpansionMap} for a detailed explanation.
720
+ */
618
721
  expand() {
619
722
  return {
620
- ...(__classPrivateFieldGet(this, _Descriptor_expandedExpression, "f") !== undefined
621
- ? { expandedExpression: __classPrivateFieldGet(this, _Descriptor_expandedExpression, "f") }
723
+ ...(__classPrivateFieldGet(this, _Output_expandedExpression, "f") !== undefined
724
+ ? { expandedExpression: __classPrivateFieldGet(this, _Output_expandedExpression, "f") }
622
725
  : {}),
623
- ...(__classPrivateFieldGet(this, _Descriptor_miniscript, "f") !== undefined
624
- ? { miniscript: __classPrivateFieldGet(this, _Descriptor_miniscript, "f") }
726
+ ...(__classPrivateFieldGet(this, _Output_miniscript, "f") !== undefined
727
+ ? { miniscript: __classPrivateFieldGet(this, _Output_miniscript, "f") }
625
728
  : {}),
626
- ...(__classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f") !== undefined
627
- ? { expandedMiniscript: __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f") }
729
+ ...(__classPrivateFieldGet(this, _Output_expandedMiniscript, "f") !== undefined
730
+ ? { expandedMiniscript: __classPrivateFieldGet(this, _Output_expandedMiniscript, "f") }
628
731
  : {}),
629
- ...(__classPrivateFieldGet(this, _Descriptor_expansionMap, "f") !== undefined
630
- ? { expansionMap: __classPrivateFieldGet(this, _Descriptor_expansionMap, "f") }
732
+ ...(__classPrivateFieldGet(this, _Output_expansionMap, "f") !== undefined
733
+ ? { expansionMap: __classPrivateFieldGet(this, _Output_expansionMap, "f") }
631
734
  : {})
632
735
  };
633
736
  }
634
737
  }
635
- _Descriptor_payment = new WeakMap(), _Descriptor_preimages = new WeakMap(), _Descriptor_signersPubKeys = new WeakMap(), _Descriptor_miniscript = new WeakMap(), _Descriptor_witnessScript = new WeakMap(), _Descriptor_redeemScript = new WeakMap(), _Descriptor_isSegwit = new WeakMap(), _Descriptor_expandedExpression = new WeakMap(), _Descriptor_expandedMiniscript = new WeakMap(), _Descriptor_expansionMap = new WeakMap(), _Descriptor_network = new WeakMap(), _Descriptor_instances = new WeakSet(), _Descriptor_getTimeConstraints = function _Descriptor_getTimeConstraints() {
636
- const miniscript = __classPrivateFieldGet(this, _Descriptor_miniscript, "f");
637
- const preimages = __classPrivateFieldGet(this, _Descriptor_preimages, "f");
638
- const expandedMiniscript = __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f");
639
- const expansionMap = __classPrivateFieldGet(this, _Descriptor_expansionMap, "f");
640
- const signersPubKeys = __classPrivateFieldGet(this, _Descriptor_signersPubKeys, "f");
738
+ _Output_payment = new WeakMap(), _Output_preimages = new WeakMap(), _Output_signersPubKeys = new WeakMap(), _Output_miniscript = new WeakMap(), _Output_witnessScript = new WeakMap(), _Output_redeemScript = new WeakMap(), _Output_isSegwit = new WeakMap(), _Output_expandedExpression = new WeakMap(), _Output_expandedMiniscript = new WeakMap(), _Output_expansionMap = new WeakMap(), _Output_network = new WeakMap(), _Output_instances = new WeakSet(), _Output_getTimeConstraints = function _Output_getTimeConstraints() {
739
+ const miniscript = __classPrivateFieldGet(this, _Output_miniscript, "f");
740
+ const preimages = __classPrivateFieldGet(this, _Output_preimages, "f");
741
+ const expandedMiniscript = __classPrivateFieldGet(this, _Output_expandedMiniscript, "f");
742
+ const expansionMap = __classPrivateFieldGet(this, _Output_expansionMap, "f");
743
+ const signersPubKeys = __classPrivateFieldGet(this, _Output_signersPubKeys, "f");
641
744
  //Create a method. solvePreimages to solve them.
642
745
  if (miniscript) {
643
746
  if (expandedMiniscript === undefined || expansionMap === undefined)
@@ -659,7 +762,7 @@ function DescriptorsFactory(ecc) {
659
762
  }
660
763
  else
661
764
  return undefined;
662
- }, _Descriptor_assertPsbtInput = function _Descriptor_assertPsbtInput({ psbt, index }) {
765
+ }, _Output_assertPsbtInput = function _Output_assertPsbtInput({ psbt, index }) {
663
766
  const input = psbt.data.inputs[index];
664
767
  const txInput = psbt.txInputs[index];
665
768
  if (!input || !txInput)
@@ -683,14 +786,34 @@ function DescriptorsFactory(ecc) {
683
786
  sequence = 0xfffffffe;
684
787
  if (sequence === undefined && locktime === 0)
685
788
  sequence = 0xffffffff;
789
+ const eqBuffers = (buf1, buf2) => buf1 instanceof Buffer && buf2 instanceof Buffer
790
+ ? Buffer.compare(buf1, buf2) === 0
791
+ : buf1 === buf2;
686
792
  if (Buffer.compare(scriptPubKey, this.getScriptPubKey()) !== 0 ||
687
793
  sequence !== inputSequence ||
688
794
  locktime !== psbt.locktime ||
689
- this.getWitnessScript() !== input.witnessScript ||
690
- this.getRedeemScript() !== input.redeemScript) {
795
+ !eqBuffers(this.getWitnessScript(), input.witnessScript) ||
796
+ !eqBuffers(this.getRedeemScript(), input.redeemScript)) {
691
797
  throw new Error(`Error: cannot finalize psbt index ${index} since it does not correspond to this descriptor`);
692
798
  }
693
799
  };
694
- return { Descriptor, parseKeyExpression, expand, ECPair, BIP32 };
800
+ /**
801
+ * @hidden
802
+ * @deprecated Use `Output` instead
803
+ */
804
+ class Descriptor extends Output {
805
+ constructor({ expression, ...rest }) {
806
+ super({ descriptor: expression, ...rest });
807
+ }
808
+ }
809
+ return {
810
+ // deprecated TAG must also be below so it is exported to descriptors.d.ts
811
+ /** @deprecated */ Descriptor,
812
+ Output,
813
+ parseKeyExpression,
814
+ expand,
815
+ ECPair,
816
+ BIP32
817
+ };
695
818
  }
696
819
  exports.DescriptorsFactory = DescriptorsFactory;