@bitcoinerlab/descriptors 0.2.1 → 0.3.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.
@@ -95,7 +95,6 @@ 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
- * @returns {Object} an object containing functions, `parse` and `checksum`.
99
98
  * @namespace
100
99
  */
101
100
  function DescriptorsFactory(ecc) {
@@ -115,6 +114,264 @@ function DescriptorsFactory(ecc) {
115
114
  BIP32
116
115
  });
117
116
  };
117
+ /**
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
+ *
136
+ * @throws {Error} Throws an error if the descriptor cannot be parsed or does not conform to the expected format.
137
+ */
138
+ const expand = ({ expression, loggedExpression, //this is the expression that will be used for logging error messages
139
+ network = bitcoinjs_lib_1.networks.bitcoin, allowMiniscriptInP2SH = false }) => {
140
+ //remove the checksum before proceeding:
141
+ expression = expression.replace(new RegExp(RE.reChecksum + '$'), '');
142
+ let expandedExpression;
143
+ let miniscript;
144
+ let expansionMap;
145
+ let isSegwit;
146
+ let expandedMiniscript;
147
+ let payment;
148
+ let witnessScript;
149
+ let redeemScript;
150
+ const isRanged = expression.indexOf('*') !== -1;
151
+ if (!loggedExpression)
152
+ loggedExpression = expression;
153
+ //addr(ADDR)
154
+ if (expression.match(RE.reAddrAnchored)) {
155
+ if (isRanged)
156
+ throw new Error(`Error: addr() cannot be ranged`);
157
+ const matchedAddress = expression.match(RE.reAddrAnchored)?.[1]; //[1]-> whatever is found addr(->HERE<-)
158
+ if (!matchedAddress)
159
+ throw new Error(`Error: could not get an address in ${loggedExpression}`);
160
+ let output;
161
+ try {
162
+ output = bitcoinjs_lib_1.address.toOutputScript(matchedAddress, network);
163
+ }
164
+ catch (e) {
165
+ throw new Error(`Error: invalid address ${matchedAddress}`);
166
+ }
167
+ try {
168
+ payment = p2pkh({ output, network });
169
+ }
170
+ catch (e) { }
171
+ try {
172
+ payment = p2sh({ output, network });
173
+ }
174
+ catch (e) { }
175
+ try {
176
+ payment = p2wpkh({ output, network });
177
+ }
178
+ catch (e) { }
179
+ try {
180
+ payment = p2wsh({ output, network });
181
+ }
182
+ catch (e) { }
183
+ try {
184
+ payment = p2tr({ output, network });
185
+ }
186
+ catch (e) { }
187
+ if (!payment) {
188
+ throw new Error(`Error: invalid address ${matchedAddress}`);
189
+ }
190
+ }
191
+ //pk(KEY)
192
+ else if (expression.match(RE.rePkAnchored)) {
193
+ isSegwit = false;
194
+ const keyExpression = expression.match(RE.reKeyExp)?.[0];
195
+ if (!keyExpression)
196
+ throw new Error(`Error: keyExpression could not me extracted`);
197
+ if (expression !== `pk(${keyExpression})`)
198
+ throw new Error(`Error: invalid expression ${loggedExpression}`);
199
+ expandedExpression = 'pk(@0)';
200
+ expansionMap = {
201
+ '@0': parseKeyExpression({ keyExpression, network, isSegwit })
202
+ };
203
+ if (!isRanged) {
204
+ const pubkey = expansionMap['@0'].pubkey;
205
+ //Note there exists no address for p2pk, but we can still use the script
206
+ if (!pubkey)
207
+ throw new Error(`Error: could not extract a pubkey from ${loggedExpression}`);
208
+ payment = p2pk({ pubkey, network });
209
+ }
210
+ }
211
+ //pkh(KEY) - legacy
212
+ else if (expression.match(RE.rePkhAnchored)) {
213
+ isSegwit = false;
214
+ const keyExpression = expression.match(RE.reKeyExp)?.[0];
215
+ if (!keyExpression)
216
+ throw new Error(`Error: keyExpression could not me extracted`);
217
+ if (expression !== `pkh(${keyExpression})`)
218
+ throw new Error(`Error: invalid expression ${loggedExpression}`);
219
+ expandedExpression = 'pkh(@0)';
220
+ expansionMap = {
221
+ '@0': parseKeyExpression({ keyExpression, network, isSegwit })
222
+ };
223
+ if (!isRanged) {
224
+ const pubkey = expansionMap['@0'].pubkey;
225
+ if (!pubkey)
226
+ throw new Error(`Error: could not extract a pubkey from ${loggedExpression}`);
227
+ payment = p2pkh({ pubkey, network });
228
+ }
229
+ }
230
+ //sh(wpkh(KEY)) - nested segwit
231
+ else if (expression.match(RE.reShWpkhAnchored)) {
232
+ isSegwit = true;
233
+ const keyExpression = expression.match(RE.reKeyExp)?.[0];
234
+ if (!keyExpression)
235
+ throw new Error(`Error: keyExpression could not me extracted`);
236
+ if (expression !== `sh(wpkh(${keyExpression}))`)
237
+ throw new Error(`Error: invalid expression ${loggedExpression}`);
238
+ expandedExpression = 'sh(wpkh(@0))';
239
+ expansionMap = {
240
+ '@0': parseKeyExpression({ keyExpression, network, isSegwit })
241
+ };
242
+ if (!isRanged) {
243
+ const pubkey = expansionMap['@0'].pubkey;
244
+ if (!pubkey)
245
+ throw new Error(`Error: could not extract a pubkey from ${loggedExpression}`);
246
+ payment = p2sh({ redeem: p2wpkh({ pubkey, network }), network });
247
+ redeemScript = payment.redeem?.output;
248
+ if (!redeemScript)
249
+ throw new Error(`Error: could not calculate redeemScript for ${loggedExpression}`);
250
+ }
251
+ }
252
+ //wpkh(KEY) - native segwit
253
+ else if (expression.match(RE.reWpkhAnchored)) {
254
+ isSegwit = true;
255
+ const keyExpression = expression.match(RE.reKeyExp)?.[0];
256
+ if (!keyExpression)
257
+ throw new Error(`Error: keyExpression could not me extracted`);
258
+ if (expression !== `wpkh(${keyExpression})`)
259
+ throw new Error(`Error: invalid expression ${loggedExpression}`);
260
+ expandedExpression = 'wpkh(@0)';
261
+ expansionMap = {
262
+ '@0': parseKeyExpression({ keyExpression, network, isSegwit })
263
+ };
264
+ if (!isRanged) {
265
+ const pubkey = expansionMap['@0'].pubkey;
266
+ if (!pubkey)
267
+ throw new Error(`Error: could not extract a pubkey from ${loggedExpression}`);
268
+ payment = p2wpkh({ pubkey, network });
269
+ }
270
+ }
271
+ //sh(wsh(miniscript))
272
+ else if (expression.match(RE.reShWshMiniscriptAnchored)) {
273
+ isSegwit = true;
274
+ miniscript = expression.match(RE.reShWshMiniscriptAnchored)?.[1]; //[1]-> whatever is found sh(wsh(->HERE<-))
275
+ if (!miniscript)
276
+ throw new Error(`Error: could not get miniscript in ${loggedExpression}`);
277
+ ({ expandedMiniscript, expansionMap } = expandMiniscript({
278
+ miniscript,
279
+ isSegwit,
280
+ network
281
+ }));
282
+ expandedExpression = `sh(wsh(${expandedMiniscript}))`;
283
+ if (!isRanged) {
284
+ const script = (0, miniscript_1.miniscript2Script)({ expandedMiniscript, expansionMap });
285
+ witnessScript = script;
286
+ if (script.byteLength > MAX_STANDARD_P2WSH_SCRIPT_SIZE) {
287
+ throw new Error(`Error: script is too large, ${script.byteLength} bytes is larger than ${MAX_STANDARD_P2WSH_SCRIPT_SIZE} bytes`);
288
+ }
289
+ const nonPushOnlyOps = countNonPushOnlyOPs(script);
290
+ if (nonPushOnlyOps > MAX_OPS_PER_SCRIPT) {
291
+ throw new Error(`Error: too many non-push ops, ${nonPushOnlyOps} non-push ops is larger than ${MAX_OPS_PER_SCRIPT}`);
292
+ }
293
+ payment = p2sh({
294
+ redeem: p2wsh({ redeem: { output: script, network }, network }),
295
+ network
296
+ });
297
+ redeemScript = payment.redeem?.output;
298
+ if (!redeemScript)
299
+ throw new Error(`Error: could not calculate redeemScript for ${loggedExpression}`);
300
+ }
301
+ }
302
+ //sh(miniscript)
303
+ else if (expression.match(RE.reShMiniscriptAnchored)) {
304
+ //isSegwit false because we know it's a P2SH of a miniscript and not a
305
+ //P2SH that embeds a witness payment.
306
+ isSegwit = false;
307
+ miniscript = expression.match(RE.reShMiniscriptAnchored)?.[1]; //[1]-> whatever is found sh(->HERE<-)
308
+ if (!miniscript)
309
+ throw new Error(`Error: could not get miniscript in ${loggedExpression}`);
310
+ if (allowMiniscriptInP2SH === false &&
311
+ //These top-level expressions within sh are allowed within sh.
312
+ //They can be parsed with miniscript2Script, but first we must make sure
313
+ //that other expressions are not accepted (unless forced with allowMiniscriptInP2SH).
314
+ miniscript.search(/^(pk\(|pkh\(|wpkh\(|combo\(|multi\(|sortedmulti\(|multi_a\(|sortedmulti_a\()/) !== 0) {
315
+ throw new Error(`Error: Miniscript expressions can only be used in wsh`);
316
+ }
317
+ ({ expandedMiniscript, expansionMap } = expandMiniscript({
318
+ miniscript,
319
+ isSegwit,
320
+ network
321
+ }));
322
+ expandedExpression = `sh(${expandedMiniscript})`;
323
+ if (!isRanged) {
324
+ const script = (0, miniscript_1.miniscript2Script)({ expandedMiniscript, expansionMap });
325
+ redeemScript = script;
326
+ if (script.byteLength > MAX_SCRIPT_ELEMENT_SIZE) {
327
+ throw new Error(`Error: P2SH script is too large, ${script.byteLength} bytes is larger than ${MAX_SCRIPT_ELEMENT_SIZE} bytes`);
328
+ }
329
+ const nonPushOnlyOps = countNonPushOnlyOPs(script);
330
+ if (nonPushOnlyOps > MAX_OPS_PER_SCRIPT) {
331
+ throw new Error(`Error: too many non-push ops, ${nonPushOnlyOps} non-push ops is larger than ${MAX_OPS_PER_SCRIPT}`);
332
+ }
333
+ payment = p2sh({ redeem: { output: script, network }, network });
334
+ }
335
+ }
336
+ //wsh(miniscript)
337
+ else if (expression.match(RE.reWshMiniscriptAnchored)) {
338
+ isSegwit = true;
339
+ miniscript = expression.match(RE.reWshMiniscriptAnchored)?.[1]; //[1]-> whatever is found wsh(->HERE<-)
340
+ if (!miniscript)
341
+ throw new Error(`Error: could not get miniscript in ${loggedExpression}`);
342
+ ({ expandedMiniscript, expansionMap } = expandMiniscript({
343
+ miniscript,
344
+ isSegwit,
345
+ network
346
+ }));
347
+ expandedExpression = `wsh(${expandedMiniscript})`;
348
+ if (!isRanged) {
349
+ const script = (0, miniscript_1.miniscript2Script)({ expandedMiniscript, expansionMap });
350
+ witnessScript = script;
351
+ if (script.byteLength > MAX_STANDARD_P2WSH_SCRIPT_SIZE) {
352
+ throw new Error(`Error: script is too large, ${script.byteLength} bytes is larger than ${MAX_STANDARD_P2WSH_SCRIPT_SIZE} bytes`);
353
+ }
354
+ const nonPushOnlyOps = countNonPushOnlyOPs(script);
355
+ if (nonPushOnlyOps > MAX_OPS_PER_SCRIPT) {
356
+ throw new Error(`Error: too many non-push ops, ${nonPushOnlyOps} non-push ops is larger than ${MAX_OPS_PER_SCRIPT}`);
357
+ }
358
+ payment = p2wsh({ redeem: { output: script, network }, network });
359
+ }
360
+ }
361
+ else {
362
+ throw new Error(`Error: Could not parse descriptor ${loggedExpression}`);
363
+ }
364
+ return {
365
+ ...(payment !== undefined ? { payment } : {}),
366
+ ...(expandedExpression !== undefined ? { expandedExpression } : {}),
367
+ ...(miniscript !== undefined ? { miniscript } : {}),
368
+ ...(expansionMap !== undefined ? { expansionMap } : {}),
369
+ ...(isSegwit !== undefined ? { isSegwit } : {}),
370
+ ...(expandedMiniscript !== undefined ? { expandedMiniscript } : {}),
371
+ ...(redeemScript !== undefined ? { redeemScript } : {}),
372
+ ...(witnessScript !== undefined ? { witnessScript } : {})
373
+ };
374
+ };
118
375
  /**
119
376
  * Expand a miniscript to a generalized form using variables instead of key
120
377
  * expressions. Variables will be of this form: @0, @1, ...
@@ -133,17 +390,18 @@ function DescriptorsFactory(ecc) {
133
390
  }
134
391
  class Descriptor {
135
392
  /**
136
- * @param {Object} params
393
+ * @param {DescriptorInfo} params
394
+ * @param {string} params.expression - The descriptor string in ASCII format. It may include a "*" to denote an arbitrary index.
137
395
  * @param {number} params.index - The descriptor's index in the case of a range descriptor (must be an interger >=0).
138
- * @param {string} params.descriptor - The descriptor.
139
396
  * @param {boolean} [params.checksumRequired=false] - A flag indicating whether the descriptor is required to include a checksum.
397
+ * @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.
140
398
  * @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).
399
+ * @param {Preimage[]} [params.preimages=[]] An array of preimages. This info is necessary to finalize Psbts.
400
+ * @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).
141
401
  *
142
- * @see {@link https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/payments/index.d.ts}
143
402
  * @throws {Error} - when descriptor is invalid
144
403
  */
145
404
  constructor({ expression, index, checksumRequired = false, allowMiniscriptInP2SH = false, network = bitcoinjs_lib_1.networks.bitcoin, preimages = [], signersPubKeys }) {
146
- var _a, _b, _c, _d, _e, _f;
147
405
  _Descriptor_instances.add(this);
148
406
  _Descriptor_payment.set(this, void 0);
149
407
  _Descriptor_preimages.set(this, []);
@@ -169,242 +427,40 @@ function DescriptorsFactory(ecc) {
169
427
  ...(index !== undefined ? { index } : {}),
170
428
  checksumRequired
171
429
  });
172
- //addr(ADDR)
173
- if (evaluatedExpression.match(RE.reAddrAnchored)) {
174
- const matchedAddress = evaluatedExpression.match(RE.reAddrAnchored)?.[1]; //[1]-> whatever is found addr(->HERE<-)
175
- if (!matchedAddress)
176
- throw new Error(`Error: could not get an address in ${evaluatedExpression}`);
177
- let output;
178
- let payment;
179
- try {
180
- output = bitcoinjs_lib_1.address.toOutputScript(matchedAddress, network);
181
- }
182
- catch (e) {
183
- throw new Error(`Error: invalid address ${matchedAddress}`);
184
- }
185
- try {
186
- payment = p2pkh({ output, network });
187
- }
188
- catch (e) { }
189
- try {
190
- payment = p2sh({ output, network });
191
- }
192
- catch (e) { }
193
- try {
194
- payment = p2wpkh({ output, network });
195
- }
196
- catch (e) { }
197
- try {
198
- payment = p2wsh({ output, network });
199
- }
200
- catch (e) { }
201
- try {
202
- payment = p2tr({ output, network });
203
- }
204
- catch (e) { }
205
- if (!payment) {
206
- throw new Error(`Error: invalid address ${matchedAddress}`);
207
- }
208
- __classPrivateFieldSet(this, _Descriptor_payment, payment, "f");
209
- }
210
- //pk(KEY)
211
- else if (evaluatedExpression.match(RE.rePkAnchored)) {
212
- __classPrivateFieldSet(this, _Descriptor_isSegwit, false, "f");
213
- const keyExpression = evaluatedExpression.match(RE.reKeyExp)?.[0];
214
- if (!keyExpression)
215
- throw new Error(`Error: keyExpression could not me extracted`);
216
- if (evaluatedExpression !== `pk(${keyExpression})`)
217
- throw new Error(`Error: invalid expression ${expression}`);
218
- __classPrivateFieldSet(this, _Descriptor_expandedExpression, 'pk(@0)', "f");
219
- __classPrivateFieldSet(this, _Descriptor_expansionMap, {
220
- '@0': parseKeyExpression({
221
- keyExpression,
222
- network,
223
- isSegwit: __classPrivateFieldGet(this, _Descriptor_isSegwit, "f")
224
- })
225
- }, "f");
226
- const pubkey = __classPrivateFieldGet(this, _Descriptor_expansionMap, "f")['@0'].pubkey;
227
- //Note there exists no address for p2pk, but we can still use the script
228
- __classPrivateFieldSet(this, _Descriptor_payment, p2pk({ pubkey, network }), "f");
229
- }
230
- //pkh(KEY) - legacy
231
- else if (evaluatedExpression.match(RE.rePkhAnchored)) {
232
- __classPrivateFieldSet(this, _Descriptor_isSegwit, false, "f");
233
- const keyExpression = evaluatedExpression.match(RE.reKeyExp)?.[0];
234
- if (!keyExpression)
235
- throw new Error(`Error: keyExpression could not me extracted`);
236
- if (evaluatedExpression !== `pkh(${keyExpression})`)
237
- throw new Error(`Error: invalid expression ${expression}`);
238
- __classPrivateFieldSet(this, _Descriptor_expandedExpression, 'pkh(@0)', "f");
239
- __classPrivateFieldSet(this, _Descriptor_expansionMap, {
240
- '@0': parseKeyExpression({
241
- keyExpression,
242
- network,
243
- isSegwit: __classPrivateFieldGet(this, _Descriptor_isSegwit, "f")
244
- })
245
- }, "f");
246
- const pubkey = __classPrivateFieldGet(this, _Descriptor_expansionMap, "f")['@0'].pubkey;
247
- __classPrivateFieldSet(this, _Descriptor_payment, p2pkh({ pubkey, network }), "f");
248
- }
249
- //sh(wpkh(KEY)) - nested segwit
250
- else if (evaluatedExpression.match(RE.reShWpkhAnchored)) {
251
- __classPrivateFieldSet(this, _Descriptor_isSegwit, true, "f");
252
- const keyExpression = evaluatedExpression.match(RE.reKeyExp)?.[0];
253
- if (!keyExpression)
254
- throw new Error(`Error: keyExpression could not me extracted`);
255
- if (evaluatedExpression !== `sh(wpkh(${keyExpression}))`)
256
- throw new Error(`Error: invalid expression ${expression}`);
257
- __classPrivateFieldSet(this, _Descriptor_expandedExpression, 'sh(wpkh(@0))', "f");
258
- __classPrivateFieldSet(this, _Descriptor_expansionMap, {
259
- '@0': parseKeyExpression({
260
- keyExpression,
261
- network,
262
- isSegwit: __classPrivateFieldGet(this, _Descriptor_isSegwit, "f")
263
- })
264
- }, "f");
265
- const pubkey = __classPrivateFieldGet(this, _Descriptor_expansionMap, "f")['@0'].pubkey;
266
- __classPrivateFieldSet(this, _Descriptor_payment, p2sh({ redeem: p2wpkh({ pubkey, network }), network }), "f");
267
- const redeemScript = __classPrivateFieldGet(this, _Descriptor_payment, "f").redeem?.output;
268
- if (!redeemScript)
269
- throw new Error(`Error: could not calculate redeemScript for ${expression}`);
270
- __classPrivateFieldSet(this, _Descriptor_redeemScript, redeemScript, "f");
271
- }
272
- //wpkh(KEY) - native segwit
273
- else if (evaluatedExpression.match(RE.reWpkhAnchored)) {
274
- __classPrivateFieldSet(this, _Descriptor_isSegwit, true, "f");
275
- const keyExpression = evaluatedExpression.match(RE.reKeyExp)?.[0];
276
- if (!keyExpression)
277
- throw new Error(`Error: keyExpression could not me extracted`);
278
- if (evaluatedExpression !== `wpkh(${keyExpression})`)
279
- throw new Error(`Error: invalid expression ${expression}`);
280
- __classPrivateFieldSet(this, _Descriptor_expandedExpression, 'wpkh(@0)', "f");
281
- __classPrivateFieldSet(this, _Descriptor_expansionMap, {
282
- '@0': parseKeyExpression({
283
- keyExpression,
284
- network,
285
- isSegwit: __classPrivateFieldGet(this, _Descriptor_isSegwit, "f")
286
- })
287
- }, "f");
288
- const pubkey = __classPrivateFieldGet(this, _Descriptor_expansionMap, "f")['@0'].pubkey;
289
- __classPrivateFieldSet(this, _Descriptor_payment, p2wpkh({ pubkey, network }), "f");
290
- }
291
- //sh(wsh(miniscript))
292
- else if (evaluatedExpression.match(RE.reShWshMiniscriptAnchored)) {
293
- __classPrivateFieldSet(this, _Descriptor_isSegwit, true, "f");
294
- const miniscript = evaluatedExpression.match(RE.reShWshMiniscriptAnchored)?.[1]; //[1]-> whatever is found sh(wsh(->HERE<-))
295
- if (!miniscript)
296
- throw new Error(`Error: could not get miniscript in ${evaluatedExpression}`);
297
- __classPrivateFieldSet(this, _Descriptor_miniscript, miniscript, "f");
298
- (_a = this, _b = this, {
299
- expandedMiniscript: ({ set value(_g) { __classPrivateFieldSet(_a, _Descriptor_expandedMiniscript, _g, "f"); } }).value,
300
- expansionMap: ({ set value(_g) { __classPrivateFieldSet(_b, _Descriptor_expansionMap, _g, "f"); } }).value
301
- } = expandMiniscript({
302
- miniscript,
303
- isSegwit: __classPrivateFieldGet(this, _Descriptor_isSegwit, "f"),
304
- network
305
- }));
306
- __classPrivateFieldSet(this, _Descriptor_expandedExpression, `sh(wsh(${__classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f")}))`, "f");
307
- const script = (0, miniscript_1.miniscript2Script)({
308
- expandedMiniscript: __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f"),
309
- expansionMap: __classPrivateFieldGet(this, _Descriptor_expansionMap, "f")
310
- });
311
- __classPrivateFieldSet(this, _Descriptor_witnessScript, script, "f");
312
- if (script.byteLength > MAX_STANDARD_P2WSH_SCRIPT_SIZE) {
313
- throw new Error(`Error: script is too large, ${script.byteLength} bytes is larger than ${MAX_STANDARD_P2WSH_SCRIPT_SIZE} bytes`);
314
- }
315
- const nonPushOnlyOps = countNonPushOnlyOPs(script);
316
- if (nonPushOnlyOps > MAX_OPS_PER_SCRIPT) {
317
- throw new Error(`Error: too many non-push ops, ${nonPushOnlyOps} non-push ops is larger than ${MAX_OPS_PER_SCRIPT}`);
318
- }
319
- __classPrivateFieldSet(this, _Descriptor_payment, p2sh({
320
- redeem: p2wsh({ redeem: { output: script, network }, network }),
321
- network
322
- }), "f");
323
- const redeemScript = __classPrivateFieldGet(this, _Descriptor_payment, "f").redeem?.output;
324
- if (!redeemScript)
325
- throw new Error(`Error: could not calculate redeemScript for ${expression}`);
326
- __classPrivateFieldSet(this, _Descriptor_redeemScript, redeemScript, "f");
327
- }
328
- //sh(miniscript)
329
- else if (evaluatedExpression.match(RE.reShMiniscriptAnchored)) {
330
- //isSegwit false because we know it's a P2SH of a miniscript and not a
331
- //P2SH that embeds a witness payment.
332
- __classPrivateFieldSet(this, _Descriptor_isSegwit, false, "f");
333
- const miniscript = evaluatedExpression.match(RE.reShMiniscriptAnchored)?.[1]; //[1]-> whatever is found sh(->HERE<-)
334
- if (!miniscript)
335
- throw new Error(`Error: could not get miniscript in ${evaluatedExpression}`);
336
- if (allowMiniscriptInP2SH === false &&
337
- //These top-level expressions within sh are allowed within sh.
338
- //They can be parsed with miniscript2Script, but first we must make sure
339
- //that other expressions are not accepted (unless forced with allowMiniscriptInP2SH).
340
- miniscript.search(/^(pk\(|pkh\(|wpkh\(|combo\(|multi\(|sortedmulti\(|multi_a\(|sortedmulti_a\()/) !== 0) {
341
- throw new Error(`Error: Miniscript expressions can only be used in wsh`);
342
- }
343
- __classPrivateFieldSet(this, _Descriptor_miniscript, miniscript, "f");
344
- (_c = this, _d = this, {
345
- expandedMiniscript: ({ set value(_g) { __classPrivateFieldSet(_c, _Descriptor_expandedMiniscript, _g, "f"); } }).value,
346
- expansionMap: ({ set value(_g) { __classPrivateFieldSet(_d, _Descriptor_expansionMap, _g, "f"); } }).value
347
- } = expandMiniscript({
348
- miniscript,
349
- isSegwit: __classPrivateFieldGet(this, _Descriptor_isSegwit, "f"),
350
- network
351
- }));
352
- __classPrivateFieldSet(this, _Descriptor_expandedExpression, `sh(${__classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f")})`, "f");
353
- const script = (0, miniscript_1.miniscript2Script)({
354
- expandedMiniscript: __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f"),
355
- expansionMap: __classPrivateFieldGet(this, _Descriptor_expansionMap, "f")
356
- });
357
- __classPrivateFieldSet(this, _Descriptor_redeemScript, script, "f");
358
- if (script.byteLength > MAX_SCRIPT_ELEMENT_SIZE) {
359
- throw new Error(`Error: P2SH script is too large, ${script.byteLength} bytes is larger than ${MAX_SCRIPT_ELEMENT_SIZE} bytes`);
360
- }
361
- const nonPushOnlyOps = countNonPushOnlyOPs(script);
362
- if (nonPushOnlyOps > MAX_OPS_PER_SCRIPT) {
363
- throw new Error(`Error: too many non-push ops, ${nonPushOnlyOps} non-push ops is larger than ${MAX_OPS_PER_SCRIPT}`);
364
- }
365
- __classPrivateFieldSet(this, _Descriptor_payment, p2sh({ redeem: { output: script, network }, network }), "f");
366
- if (Buffer.compare(script, this.getRedeemScript()) !== 0)
367
- throw new Error(`Error: redeemScript was not correctly set to the payment in expression ${expression}`);
368
- }
369
- //wsh(miniscript)
370
- else if (evaluatedExpression.match(RE.reWshMiniscriptAnchored)) {
371
- __classPrivateFieldSet(this, _Descriptor_isSegwit, true, "f");
372
- const miniscript = evaluatedExpression.match(RE.reWshMiniscriptAnchored)?.[1]; //[1]-> whatever is found wsh(->HERE<-)
373
- if (!miniscript)
374
- throw new Error(`Error: could not get miniscript in ${evaluatedExpression}`);
375
- __classPrivateFieldSet(this, _Descriptor_miniscript, miniscript, "f");
376
- (_e = this, _f = this, {
377
- expandedMiniscript: ({ set value(_g) { __classPrivateFieldSet(_e, _Descriptor_expandedMiniscript, _g, "f"); } }).value,
378
- expansionMap: ({ set value(_g) { __classPrivateFieldSet(_f, _Descriptor_expansionMap, _g, "f"); } }).value
379
- } = expandMiniscript({
380
- miniscript,
381
- isSegwit: __classPrivateFieldGet(this, _Descriptor_isSegwit, "f"),
382
- network
383
- }));
384
- __classPrivateFieldSet(this, _Descriptor_expandedExpression, `wsh(${__classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f")})`, "f");
385
- const script = (0, miniscript_1.miniscript2Script)({
386
- expandedMiniscript: __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f"),
387
- expansionMap: __classPrivateFieldGet(this, _Descriptor_expansionMap, "f")
388
- });
389
- __classPrivateFieldSet(this, _Descriptor_witnessScript, script, "f");
390
- if (script.byteLength > MAX_STANDARD_P2WSH_SCRIPT_SIZE) {
391
- throw new Error(`Error: script is too large, ${script.byteLength} bytes is larger than ${MAX_STANDARD_P2WSH_SCRIPT_SIZE} bytes`);
392
- }
393
- const nonPushOnlyOps = countNonPushOnlyOPs(script);
394
- if (nonPushOnlyOps > MAX_OPS_PER_SCRIPT) {
395
- throw new Error(`Error: too many non-push ops, ${nonPushOnlyOps} non-push ops is larger than ${MAX_OPS_PER_SCRIPT}`);
396
- }
397
- __classPrivateFieldSet(this, _Descriptor_payment, p2wsh({ redeem: { output: script, network }, network }), "f");
398
- }
399
- else {
400
- throw new Error(`Error: Could not parse descriptor ${expression}`);
401
- }
430
+ const expandedResult = expand({
431
+ expression: evaluatedExpression,
432
+ loggedExpression: expression,
433
+ network,
434
+ allowMiniscriptInP2SH
435
+ });
436
+ if (!expandedResult.payment)
437
+ throw new Error(`Error: could not extract a payment from ${expression}`);
438
+ __classPrivateFieldSet(this, _Descriptor_payment, expandedResult.payment, "f");
439
+ if (expandedResult.expandedExpression !== undefined)
440
+ __classPrivateFieldSet(this, _Descriptor_expandedExpression, expandedResult.expandedExpression, "f");
441
+ if (expandedResult.miniscript !== undefined)
442
+ __classPrivateFieldSet(this, _Descriptor_miniscript, expandedResult.miniscript, "f");
443
+ if (expandedResult.expansionMap !== undefined)
444
+ __classPrivateFieldSet(this, _Descriptor_expansionMap, expandedResult.expansionMap, "f");
445
+ if (expandedResult.isSegwit !== undefined)
446
+ __classPrivateFieldSet(this, _Descriptor_isSegwit, expandedResult.isSegwit, "f");
447
+ if (expandedResult.expandedMiniscript !== undefined)
448
+ __classPrivateFieldSet(this, _Descriptor_expandedMiniscript, expandedResult.expandedMiniscript, "f");
449
+ if (expandedResult.redeemScript !== undefined)
450
+ __classPrivateFieldSet(this, _Descriptor_redeemScript, expandedResult.redeemScript, "f");
451
+ if (expandedResult.witnessScript !== undefined)
452
+ __classPrivateFieldSet(this, _Descriptor_witnessScript, expandedResult.witnessScript, "f");
402
453
  if (signersPubKeys) {
403
454
  __classPrivateFieldSet(this, _Descriptor_signersPubKeys, signersPubKeys, "f");
404
455
  }
405
456
  else {
406
457
  if (__classPrivateFieldGet(this, _Descriptor_expansionMap, "f")) {
407
- __classPrivateFieldSet(this, _Descriptor_signersPubKeys, Object.values(__classPrivateFieldGet(this, _Descriptor_expansionMap, "f")).map(keyInfo => keyInfo.pubkey), "f");
458
+ __classPrivateFieldSet(this, _Descriptor_signersPubKeys, Object.values(__classPrivateFieldGet(this, _Descriptor_expansionMap, "f")).map(keyInfo => {
459
+ const pubkey = keyInfo.pubkey;
460
+ if (!pubkey)
461
+ throw new Error(`Error: could not extract a pubkey from ${expression}`);
462
+ return pubkey;
463
+ }), "f");
408
464
  }
409
465
  else {
410
466
  //We should only miss expansionMap in addr() expressions:
@@ -418,6 +474,9 @@ function DescriptorsFactory(ecc) {
418
474
  getPayment() {
419
475
  return __classPrivateFieldGet(this, _Descriptor_payment, "f");
420
476
  }
477
+ /**
478
+ * Returns the Bitcoin Address
479
+ */
421
480
  getAddress() {
422
481
  if (!__classPrivateFieldGet(this, _Descriptor_payment, "f").address)
423
482
  throw new Error(`Error: could extract an address from the payment`);
@@ -428,6 +487,11 @@ function DescriptorsFactory(ecc) {
428
487
  throw new Error(`Error: could extract output.script from the payment`);
429
488
  return __classPrivateFieldGet(this, _Descriptor_payment, "f").output;
430
489
  }
490
+ /**
491
+ * Returns the compiled script satisfaction
492
+ * @param {PartialSig[]} signatures An array of signatures using this format: `interface PartialSig { pubkey: Buffer; signature: Buffer; }`
493
+ * @returns {Buffer}
494
+ */
431
495
  getScriptSatisfaction(signatures) {
432
496
  const miniscript = __classPrivateFieldGet(this, _Descriptor_miniscript, "f");
433
497
  const expandedMiniscript = __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f");
@@ -622,6 +686,6 @@ function DescriptorsFactory(ecc) {
622
686
  throw new Error(`Error: cannot finalize psbt index ${index} since it does not correspond to this descriptor`);
623
687
  }
624
688
  };
625
- return { Descriptor, parseKeyExpression, ECPair, BIP32 };
689
+ return { Descriptor, parseKeyExpression, expand, ECPair, BIP32 };
626
690
  }
627
691
  exports.DescriptorsFactory = DescriptorsFactory;
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ export declare function finalizePsbt({ psbt, descriptors, validate }: {
13
13
  export { keyExpressionBIP32, keyExpressionLedger } from './keyExpressions';
14
14
  import * as scriptExpressions from './scriptExpressions';
15
15
  export { scriptExpressions };
16
- import { AppClient } from '@bitcoinerlab/ledger';
16
+ import { AppClient } from 'ledger-bitcoin';
17
17
  import { LedgerState, getLedgerMasterFingerPrint, getLedgerXpub, registerLedgerWallet, assertLedgerApp } from './ledger';
18
18
  export declare const ledger: {
19
19
  getLedgerMasterFingerPrint: typeof getLedgerMasterFingerPrint;
package/dist/index.js CHANGED
@@ -42,12 +42,12 @@ Object.defineProperty(exports, "keyExpressionBIP32", { enumerable: true, get: fu
42
42
  Object.defineProperty(exports, "keyExpressionLedger", { enumerable: true, get: function () { return keyExpressions_1.keyExpressionLedger; } });
43
43
  const scriptExpressions = __importStar(require("./scriptExpressions"));
44
44
  exports.scriptExpressions = scriptExpressions;
45
- const ledger_1 = require("@bitcoinerlab/ledger");
46
- const ledger_2 = require("./ledger");
45
+ const ledger_bitcoin_1 = require("ledger-bitcoin");
46
+ const ledger_1 = require("./ledger");
47
47
  exports.ledger = {
48
- getLedgerMasterFingerPrint: ledger_2.getLedgerMasterFingerPrint,
49
- getLedgerXpub: ledger_2.getLedgerXpub,
50
- registerLedgerWallet: ledger_2.registerLedgerWallet,
51
- assertLedgerApp: ledger_2.assertLedgerApp,
52
- AppClient: ledger_1.AppClient
48
+ getLedgerMasterFingerPrint: ledger_1.getLedgerMasterFingerPrint,
49
+ getLedgerXpub: ledger_1.getLedgerXpub,
50
+ registerLedgerWallet: ledger_1.registerLedgerWallet,
51
+ assertLedgerApp: ledger_1.assertLedgerApp,
52
+ AppClient: ledger_bitcoin_1.AppClient
53
53
  };
@@ -3,7 +3,7 @@ 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
- import type { AppClient } from '@bitcoinerlab/ledger';
6
+ import type { AppClient } from 'ledger-bitcoin';
7
7
  export declare function parseKeyExpression({ keyExpression, isSegwit, ECPair, BIP32, network }: {
8
8
  keyExpression: string;
9
9
  network?: Network;