@bitcoinerlab/descriptors 1.1.1 → 2.0.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.
@@ -60,44 +60,68 @@ 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).
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).
98
122
  */
99
123
  function DescriptorsFactory(ecc) {
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;
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;
101
125
  const BIP32 = (0, bip32_1.BIP32Factory)(ecc);
102
126
  const ECPair = (0, ecpair_1.ECPairFactory)(ecc);
103
127
  const signatureValidator = (pubkey, msghash, signature) => ECPair.fromPublicKey(pubkey).verify(msghash, signature);
@@ -114,11 +138,16 @@ function DescriptorsFactory(ecc) {
114
138
  });
115
139
  };
116
140
  /**
117
- * Takes a descriptor (expression) and expands it to its corresponding Bitcoin script and other relevant details.
118
- *
119
- * @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
120
144
  */
121
- 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`);
122
151
  let expandedExpression;
123
152
  let miniscript;
124
153
  let expansionMap;
@@ -127,14 +156,14 @@ function DescriptorsFactory(ecc) {
127
156
  let payment;
128
157
  let witnessScript;
129
158
  let redeemScript;
130
- const isRanged = expression.indexOf('*') !== -1;
159
+ const isRanged = descriptor.indexOf('*') !== -1;
131
160
  if (index !== undefined)
132
161
  if (!Number.isInteger(index) || index < 0)
133
162
  throw new Error(`Error: invalid index ${index}`);
134
163
  //Verify and remove checksum (if exists) and
135
164
  //particularize range descriptor for index (if desc is range descriptor)
136
165
  const canonicalExpression = evaluate({
137
- expression,
166
+ descriptor,
138
167
  ...(index !== undefined ? { index } : {}),
139
168
  checksumRequired
140
169
  });
@@ -145,7 +174,7 @@ function DescriptorsFactory(ecc) {
145
174
  throw new Error(`Error: addr() cannot be ranged`);
146
175
  const matchedAddress = canonicalExpression.match(RE.reAddrAnchored)?.[1]; //[1]-> whatever is found addr(->HERE<-)
147
176
  if (!matchedAddress)
148
- throw new Error(`Error: could not get an address in ${expression}`);
177
+ throw new Error(`Error: could not get an address in ${descriptor}`);
149
178
  let output;
150
179
  try {
151
180
  output = bitcoinjs_lib_1.address.toOutputScript(matchedAddress, network);
@@ -184,7 +213,7 @@ function DescriptorsFactory(ecc) {
184
213
  if (!keyExpression)
185
214
  throw new Error(`Error: keyExpression could not me extracted`);
186
215
  if (canonicalExpression !== `pk(${keyExpression})`)
187
- throw new Error(`Error: invalid expression ${expression}`);
216
+ throw new Error(`Error: invalid expression ${descriptor}`);
188
217
  expandedExpression = 'pk(@0)';
189
218
  const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
190
219
  expansionMap = { '@0': pKE };
@@ -192,7 +221,7 @@ function DescriptorsFactory(ecc) {
192
221
  const pubkey = pKE.pubkey;
193
222
  //Note there exists no address for p2pk, but we can still use the script
194
223
  if (!pubkey)
195
- throw new Error(`Error: could not extract a pubkey from ${expression}`);
224
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
196
225
  payment = p2pk({ pubkey, network });
197
226
  }
198
227
  }
@@ -203,14 +232,14 @@ function DescriptorsFactory(ecc) {
203
232
  if (!keyExpression)
204
233
  throw new Error(`Error: keyExpression could not me extracted`);
205
234
  if (canonicalExpression !== `pkh(${keyExpression})`)
206
- throw new Error(`Error: invalid expression ${expression}`);
235
+ throw new Error(`Error: invalid expression ${descriptor}`);
207
236
  expandedExpression = 'pkh(@0)';
208
237
  const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
209
238
  expansionMap = { '@0': pKE };
210
239
  if (!isCanonicalRanged) {
211
240
  const pubkey = pKE.pubkey;
212
241
  if (!pubkey)
213
- throw new Error(`Error: could not extract a pubkey from ${expression}`);
242
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
214
243
  payment = p2pkh({ pubkey, network });
215
244
  }
216
245
  }
@@ -221,18 +250,18 @@ function DescriptorsFactory(ecc) {
221
250
  if (!keyExpression)
222
251
  throw new Error(`Error: keyExpression could not me extracted`);
223
252
  if (canonicalExpression !== `sh(wpkh(${keyExpression}))`)
224
- throw new Error(`Error: invalid expression ${expression}`);
253
+ throw new Error(`Error: invalid expression ${descriptor}`);
225
254
  expandedExpression = 'sh(wpkh(@0))';
226
255
  const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
227
256
  expansionMap = { '@0': pKE };
228
257
  if (!isCanonicalRanged) {
229
258
  const pubkey = pKE.pubkey;
230
259
  if (!pubkey)
231
- throw new Error(`Error: could not extract a pubkey from ${expression}`);
260
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
232
261
  payment = p2sh({ redeem: p2wpkh({ pubkey, network }), network });
233
262
  redeemScript = payment.redeem?.output;
234
263
  if (!redeemScript)
235
- throw new Error(`Error: could not calculate redeemScript for ${expression}`);
264
+ throw new Error(`Error: could not calculate redeemScript for ${descriptor}`);
236
265
  }
237
266
  }
238
267
  //wpkh(KEY) - native segwit
@@ -242,14 +271,14 @@ function DescriptorsFactory(ecc) {
242
271
  if (!keyExpression)
243
272
  throw new Error(`Error: keyExpression could not me extracted`);
244
273
  if (canonicalExpression !== `wpkh(${keyExpression})`)
245
- throw new Error(`Error: invalid expression ${expression}`);
274
+ throw new Error(`Error: invalid expression ${descriptor}`);
246
275
  expandedExpression = 'wpkh(@0)';
247
276
  const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
248
277
  expansionMap = { '@0': pKE };
249
278
  if (!isCanonicalRanged) {
250
279
  const pubkey = pKE.pubkey;
251
280
  if (!pubkey)
252
- throw new Error(`Error: could not extract a pubkey from ${expression}`);
281
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
253
282
  payment = p2wpkh({ pubkey, network });
254
283
  }
255
284
  }
@@ -258,7 +287,7 @@ function DescriptorsFactory(ecc) {
258
287
  isSegwit = true;
259
288
  miniscript = canonicalExpression.match(RE.reShWshMiniscriptAnchored)?.[1]; //[1]-> whatever is found sh(wsh(->HERE<-))
260
289
  if (!miniscript)
261
- throw new Error(`Error: could not get miniscript in ${expression}`);
290
+ throw new Error(`Error: could not get miniscript in ${descriptor}`);
262
291
  ({ expandedMiniscript, expansionMap } = expandMiniscript({
263
292
  miniscript,
264
293
  isSegwit,
@@ -281,7 +310,7 @@ function DescriptorsFactory(ecc) {
281
310
  });
282
311
  redeemScript = payment.redeem?.output;
283
312
  if (!redeemScript)
284
- throw new Error(`Error: could not calculate redeemScript for ${expression}`);
313
+ throw new Error(`Error: could not calculate redeemScript for ${descriptor}`);
285
314
  }
286
315
  }
287
316
  //sh(miniscript)
@@ -291,7 +320,7 @@ function DescriptorsFactory(ecc) {
291
320
  isSegwit = false;
292
321
  miniscript = canonicalExpression.match(RE.reShMiniscriptAnchored)?.[1]; //[1]-> whatever is found sh(->HERE<-)
293
322
  if (!miniscript)
294
- throw new Error(`Error: could not get miniscript in ${expression}`);
323
+ throw new Error(`Error: could not get miniscript in ${descriptor}`);
295
324
  if (allowMiniscriptInP2SH === false &&
296
325
  //These top-level expressions within sh are allowed within sh.
297
326
  //They can be parsed with miniscript2Script, but first we must make sure
@@ -323,7 +352,7 @@ function DescriptorsFactory(ecc) {
323
352
  isSegwit = true;
324
353
  miniscript = canonicalExpression.match(RE.reWshMiniscriptAnchored)?.[1]; //[1]-> whatever is found wsh(->HERE<-)
325
354
  if (!miniscript)
326
- throw new Error(`Error: could not get miniscript in ${expression}`);
355
+ throw new Error(`Error: could not get miniscript in ${descriptor}`);
327
356
  ({ expandedMiniscript, expansionMap } = expandMiniscript({
328
357
  miniscript,
329
358
  isSegwit,
@@ -344,7 +373,7 @@ function DescriptorsFactory(ecc) {
344
373
  }
345
374
  }
346
375
  else {
347
- throw new Error(`Error: Could not parse descriptor ${expression}`);
376
+ throw new Error(`Error: Could not parse descriptor ${descriptor}`);
348
377
  }
349
378
  return {
350
379
  ...(payment !== undefined ? { payment } : {}),
@@ -358,7 +387,7 @@ function DescriptorsFactory(ecc) {
358
387
  isRanged,
359
388
  canonicalExpression
360
389
  };
361
- };
390
+ }
362
391
  /**
363
392
  * Expand a miniscript to a generalized form using variables instead of key
364
393
  * expressions. Variables will be of this form: @0, @1, ...
@@ -375,32 +404,38 @@ function DescriptorsFactory(ecc) {
375
404
  ECPair
376
405
  });
377
406
  }
378
- 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 {
379
414
  /**
380
415
  * @param options
381
416
  * @throws {Error} - when descriptor is invalid
382
417
  */
383
- constructor({ expression, index, checksumRequired = false, allowMiniscriptInP2SH = false, network = bitcoinjs_lib_1.networks.bitcoin, preimages = [], signersPubKeys }) {
384
- _Descriptor_instances.add(this);
385
- _Descriptor_payment.set(this, void 0);
386
- _Descriptor_preimages.set(this, []);
387
- _Descriptor_signersPubKeys.set(this, void 0);
388
- _Descriptor_miniscript.set(this, void 0);
389
- _Descriptor_witnessScript.set(this, void 0);
390
- _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);
391
426
  //isSegwit true if witnesses are needed to the spend coins sent to this descriptor.
392
427
  //may be unset because we may get addr(P2SH) which we don't know if they have segwit.
393
- _Descriptor_isSegwit.set(this, void 0);
394
- _Descriptor_expandedExpression.set(this, void 0);
395
- _Descriptor_expandedMiniscript.set(this, void 0);
396
- _Descriptor_expansionMap.set(this, void 0);
397
- _Descriptor_network.set(this, void 0);
398
- __classPrivateFieldSet(this, _Descriptor_network, network, "f");
399
- __classPrivateFieldSet(this, _Descriptor_preimages, preimages, "f");
400
- 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')
401
436
  throw new Error(`Error: invalid descriptor type`);
402
437
  const expandedResult = expand({
403
- expression,
438
+ descriptor,
404
439
  ...(index !== undefined ? { index } : {}),
405
440
  checksumRequired,
406
441
  network,
@@ -409,68 +444,89 @@ function DescriptorsFactory(ecc) {
409
444
  if (expandedResult.isRanged && index === undefined)
410
445
  throw new Error(`Error: index was not provided for ranged descriptor`);
411
446
  if (!expandedResult.payment)
412
- throw new Error(`Error: could not extract a payment from ${expression}`);
413
- __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");
414
449
  if (expandedResult.expandedExpression !== undefined)
415
- __classPrivateFieldSet(this, _Descriptor_expandedExpression, expandedResult.expandedExpression, "f");
450
+ __classPrivateFieldSet(this, _Output_expandedExpression, expandedResult.expandedExpression, "f");
416
451
  if (expandedResult.miniscript !== undefined)
417
- __classPrivateFieldSet(this, _Descriptor_miniscript, expandedResult.miniscript, "f");
452
+ __classPrivateFieldSet(this, _Output_miniscript, expandedResult.miniscript, "f");
418
453
  if (expandedResult.expansionMap !== undefined)
419
- __classPrivateFieldSet(this, _Descriptor_expansionMap, expandedResult.expansionMap, "f");
454
+ __classPrivateFieldSet(this, _Output_expansionMap, expandedResult.expansionMap, "f");
420
455
  if (expandedResult.isSegwit !== undefined)
421
- __classPrivateFieldSet(this, _Descriptor_isSegwit, expandedResult.isSegwit, "f");
456
+ __classPrivateFieldSet(this, _Output_isSegwit, expandedResult.isSegwit, "f");
422
457
  if (expandedResult.expandedMiniscript !== undefined)
423
- __classPrivateFieldSet(this, _Descriptor_expandedMiniscript, expandedResult.expandedMiniscript, "f");
458
+ __classPrivateFieldSet(this, _Output_expandedMiniscript, expandedResult.expandedMiniscript, "f");
424
459
  if (expandedResult.redeemScript !== undefined)
425
- __classPrivateFieldSet(this, _Descriptor_redeemScript, expandedResult.redeemScript, "f");
460
+ __classPrivateFieldSet(this, _Output_redeemScript, expandedResult.redeemScript, "f");
426
461
  if (expandedResult.witnessScript !== undefined)
427
- __classPrivateFieldSet(this, _Descriptor_witnessScript, expandedResult.witnessScript, "f");
462
+ __classPrivateFieldSet(this, _Output_witnessScript, expandedResult.witnessScript, "f");
428
463
  if (signersPubKeys) {
429
- __classPrivateFieldSet(this, _Descriptor_signersPubKeys, signersPubKeys, "f");
464
+ __classPrivateFieldSet(this, _Output_signersPubKeys, signersPubKeys, "f");
430
465
  }
431
466
  else {
432
- if (__classPrivateFieldGet(this, _Descriptor_expansionMap, "f")) {
433
- __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 => {
434
469
  const pubkey = keyInfo.pubkey;
435
470
  if (!pubkey)
436
- throw new Error(`Error: could not extract a pubkey from ${expression}`);
471
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
437
472
  return pubkey;
438
473
  }), "f");
439
474
  }
440
475
  else {
441
476
  //We should only miss expansionMap in addr() expressions:
442
477
  if (!expandedResult.canonicalExpression.match(RE.reAddrAnchored)) {
443
- 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`);
444
479
  }
445
- __classPrivateFieldSet(this, _Descriptor_signersPubKeys, [this.getScriptPubKey()], "f");
480
+ __classPrivateFieldSet(this, _Output_signersPubKeys, [this.getScriptPubKey()], "f");
446
481
  }
447
482
  }
448
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
+ */
449
488
  getPayment() {
450
- return __classPrivateFieldGet(this, _Descriptor_payment, "f");
489
+ return __classPrivateFieldGet(this, _Output_payment, "f");
451
490
  }
452
491
  /**
453
- * Returns the Bitcoin Address
492
+ * Returns the Bitcoin Address of this `Output`.
454
493
  */
455
494
  getAddress() {
456
- if (!__classPrivateFieldGet(this, _Descriptor_payment, "f").address)
495
+ if (!__classPrivateFieldGet(this, _Output_payment, "f").address)
457
496
  throw new Error(`Error: could extract an address from the payment`);
458
- return __classPrivateFieldGet(this, _Descriptor_payment, "f").address;
497
+ return __classPrivateFieldGet(this, _Output_payment, "f").address;
459
498
  }
499
+ /**
500
+ * Returns this `Output`'s scriptPubKey.
501
+ */
460
502
  getScriptPubKey() {
461
- if (!__classPrivateFieldGet(this, _Descriptor_payment, "f").output)
503
+ if (!__classPrivateFieldGet(this, _Output_payment, "f").output)
462
504
  throw new Error(`Error: could extract output.script from the payment`);
463
- return __classPrivateFieldGet(this, _Descriptor_payment, "f").output;
505
+ return __classPrivateFieldGet(this, _Output_payment, "f").output;
464
506
  }
465
507
  /**
466
- * Returns the compiled script satisfaction
467
- * @param {PartialSig[]} signatures An array of signatures using this format: `interface PartialSig { pubkey: Buffer; signature: Buffer; }`
468
- * @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.
517
+ */
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; }`
469
525
  */
470
- getScriptSatisfaction(signatures) {
471
- const miniscript = __classPrivateFieldGet(this, _Descriptor_miniscript, "f");
472
- const expandedMiniscript = __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f");
473
- const expansionMap = __classPrivateFieldGet(this, _Descriptor_expansionMap, "f");
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");
474
530
  if (miniscript === undefined ||
475
531
  expandedMiniscript === undefined ||
476
532
  expansionMap === undefined)
@@ -484,7 +540,7 @@ function DescriptorsFactory(ecc) {
484
540
  expandedMiniscript,
485
541
  expansionMap,
486
542
  signatures,
487
- preimages: __classPrivateFieldGet(this, _Descriptor_preimages, "f"),
543
+ preimages: __classPrivateFieldGet(this, _Output_preimages, "f"),
488
544
  //Here we pass the TimeConstraints obtained using signersPubKeys to
489
545
  //verify that the solutions found using the final signatures have not
490
546
  //changed
@@ -497,45 +553,76 @@ function DescriptorsFactory(ecc) {
497
553
  throw new Error(`Error: could not produce a valid satisfaction`);
498
554
  return scriptSatisfaction;
499
555
  }
556
+ /**
557
+ * Gets the nSequence required to fulfill this `Output`.
558
+ */
500
559
  getSequence() {
501
- return __classPrivateFieldGet(this, _Descriptor_instances, "m", _Descriptor_getTimeConstraints).call(this)?.nSequence;
560
+ return __classPrivateFieldGet(this, _Output_instances, "m", _Output_getTimeConstraints).call(this)?.nSequence;
502
561
  }
562
+ /**
563
+ * Gets the nLockTime required to fulfill this `Output`.
564
+ */
503
565
  getLockTime() {
504
- return __classPrivateFieldGet(this, _Descriptor_instances, "m", _Descriptor_getTimeConstraints).call(this)?.nLockTime;
566
+ return __classPrivateFieldGet(this, _Output_instances, "m", _Output_getTimeConstraints).call(this)?.nLockTime;
505
567
  }
568
+ /**
569
+ * Gets the witnessScript required to fulfill this `Output`. Only applies to
570
+ * Segwit outputs.
571
+ */
506
572
  getWitnessScript() {
507
- return __classPrivateFieldGet(this, _Descriptor_witnessScript, "f");
573
+ return __classPrivateFieldGet(this, _Output_witnessScript, "f");
508
574
  }
575
+ /**
576
+ * Gets the redeemScript required to fullfill this `Output`. Only applies to
577
+ * SH outputs: sh(wpkh), sh(wsh), sh(lockingScript).
578
+ */
509
579
  getRedeemScript() {
510
- return __classPrivateFieldGet(this, _Descriptor_redeemScript, "f");
580
+ return __classPrivateFieldGet(this, _Output_redeemScript, "f");
511
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
+ */
512
585
  getNetwork() {
513
- return __classPrivateFieldGet(this, _Descriptor_network, "f");
586
+ return __classPrivateFieldGet(this, _Output_network, "f");
514
587
  }
588
+ /**
589
+ * Whether this `Output` is Segwit.
590
+ */
515
591
  isSegwit() {
516
- 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;
517
600
  }
518
601
  /**
519
- * Updates a Psbt where the descriptor describes an utxo.
520
- * 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).
521
615
  *
522
- * updatePsbt adds an input to the psbt and updates the tx locktime if needed.
523
- * It also adds a new input to the Psbt based on txHex
524
- * It returns the number of the input that is added.
525
- * psbt and vout are mandatory. Also pass txHex.
616
+ * When unsure, always use `txHex`, and skip `txId` and `value` for safety.
526
617
  *
527
- * The following is not recommended but, alternatively, ONLY for Segwit inputs,
528
- * you can pass txId and value, instead of txHex.
529
- * If you do so, it is your responsibility to make sure that `value` is
530
- * correct to avoid possible fee vulnerability attacks:
531
- * https://github.com/bitcoinjs/bitcoinjs-lib/issues/1625
532
- * Note that HW wallets require the full txHex also for Segwit anyways:
533
- * 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`
534
623
  *
535
- * In doubt, simply pass txHex (and you can skip passing txId and value) and
536
- * you shall be fine.
537
624
  */
538
- updatePsbt({ psbt, txHex, txId, value, vout //vector output index
625
+ updatePsbtAsInput({ psbt, txHex, txId, value, vout //vector output index
539
626
  }) {
540
627
  if (txHex === undefined) {
541
628
  console.warn(`Warning: missing txHex may allow fee attacks`);
@@ -545,7 +632,7 @@ function DescriptorsFactory(ecc) {
545
632
  //This should only happen when using addr() expressions
546
633
  throw new Error(`Error: could not determine whether this is a segwit descriptor`);
547
634
  }
548
- return (0, psbt_1.updatePsbt)({
635
+ const index = (0, psbt_1.updatePsbt)({
549
636
  psbt,
550
637
  vout,
551
638
  ...(txHex !== undefined ? { txHex } : {}),
@@ -553,13 +640,55 @@ function DescriptorsFactory(ecc) {
553
640
  ...(value !== undefined ? { value } : {}),
554
641
  sequence: this.getSequence(),
555
642
  locktime: this.getLockTime(),
556
- 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")) : [],
557
644
  scriptPubKey: this.getScriptPubKey(),
558
645
  isSegwit,
559
646
  witnessScript: this.getWitnessScript(),
560
647
  redeemScript: this.getRedeemScript()
561
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 });
562
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
+ */
563
692
  finalizePsbtInput({ index, psbt, validate = true }) {
564
693
  if (validate &&
565
694
  !psbt.validateSignaturesOfInput(index, signatureValidator)) {
@@ -575,39 +704,43 @@ function DescriptorsFactory(ecc) {
575
704
  const signatures = psbt.data.inputs[index]?.partialSig;
576
705
  if (!signatures)
577
706
  throw new Error(`Error: cannot finalize without signatures`);
578
- __classPrivateFieldGet(this, _Descriptor_instances, "m", _Descriptor_assertPsbtInput).call(this, { index, psbt });
579
- 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")) {
580
709
  //Use standard finalizers
581
710
  psbt.finalizeInput(index);
582
711
  }
583
712
  else {
584
713
  const scriptSatisfaction = this.getScriptSatisfaction(signatures);
585
- 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")));
586
715
  }
587
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
+ */
588
721
  expand() {
589
722
  return {
590
- ...(__classPrivateFieldGet(this, _Descriptor_expandedExpression, "f") !== undefined
591
- ? { expandedExpression: __classPrivateFieldGet(this, _Descriptor_expandedExpression, "f") }
723
+ ...(__classPrivateFieldGet(this, _Output_expandedExpression, "f") !== undefined
724
+ ? { expandedExpression: __classPrivateFieldGet(this, _Output_expandedExpression, "f") }
592
725
  : {}),
593
- ...(__classPrivateFieldGet(this, _Descriptor_miniscript, "f") !== undefined
594
- ? { miniscript: __classPrivateFieldGet(this, _Descriptor_miniscript, "f") }
726
+ ...(__classPrivateFieldGet(this, _Output_miniscript, "f") !== undefined
727
+ ? { miniscript: __classPrivateFieldGet(this, _Output_miniscript, "f") }
595
728
  : {}),
596
- ...(__classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f") !== undefined
597
- ? { expandedMiniscript: __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f") }
729
+ ...(__classPrivateFieldGet(this, _Output_expandedMiniscript, "f") !== undefined
730
+ ? { expandedMiniscript: __classPrivateFieldGet(this, _Output_expandedMiniscript, "f") }
598
731
  : {}),
599
- ...(__classPrivateFieldGet(this, _Descriptor_expansionMap, "f") !== undefined
600
- ? { expansionMap: __classPrivateFieldGet(this, _Descriptor_expansionMap, "f") }
732
+ ...(__classPrivateFieldGet(this, _Output_expansionMap, "f") !== undefined
733
+ ? { expansionMap: __classPrivateFieldGet(this, _Output_expansionMap, "f") }
601
734
  : {})
602
735
  };
603
736
  }
604
737
  }
605
- _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() {
606
- const miniscript = __classPrivateFieldGet(this, _Descriptor_miniscript, "f");
607
- const preimages = __classPrivateFieldGet(this, _Descriptor_preimages, "f");
608
- const expandedMiniscript = __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f");
609
- const expansionMap = __classPrivateFieldGet(this, _Descriptor_expansionMap, "f");
610
- 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");
611
744
  //Create a method. solvePreimages to solve them.
612
745
  if (miniscript) {
613
746
  if (expandedMiniscript === undefined || expansionMap === undefined)
@@ -629,7 +762,7 @@ function DescriptorsFactory(ecc) {
629
762
  }
630
763
  else
631
764
  return undefined;
632
- }, _Descriptor_assertPsbtInput = function _Descriptor_assertPsbtInput({ psbt, index }) {
765
+ }, _Output_assertPsbtInput = function _Output_assertPsbtInput({ psbt, index }) {
633
766
  const input = psbt.data.inputs[index];
634
767
  const txInput = psbt.txInputs[index];
635
768
  if (!input || !txInput)
@@ -653,14 +786,34 @@ function DescriptorsFactory(ecc) {
653
786
  sequence = 0xfffffffe;
654
787
  if (sequence === undefined && locktime === 0)
655
788
  sequence = 0xffffffff;
789
+ const eqBuffers = (buf1, buf2) => buf1 instanceof Buffer && buf2 instanceof Buffer
790
+ ? Buffer.compare(buf1, buf2) === 0
791
+ : buf1 === buf2;
656
792
  if (Buffer.compare(scriptPubKey, this.getScriptPubKey()) !== 0 ||
657
793
  sequence !== inputSequence ||
658
794
  locktime !== psbt.locktime ||
659
- this.getWitnessScript() !== input.witnessScript ||
660
- this.getRedeemScript() !== input.redeemScript) {
795
+ !eqBuffers(this.getWitnessScript(), input.witnessScript) ||
796
+ !eqBuffers(this.getRedeemScript(), input.redeemScript)) {
661
797
  throw new Error(`Error: cannot finalize psbt index ${index} since it does not correspond to this descriptor`);
662
798
  }
663
799
  };
664
- 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
+ };
665
818
  }
666
819
  exports.DescriptorsFactory = DescriptorsFactory;