@bitcoinerlab/descriptors 1.1.1 → 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.
- package/README.md +138 -145
- package/dist/checksum.d.ts +4 -0
- package/dist/checksum.js +4 -0
- package/dist/descriptors.d.ts +415 -37
- package/dist/descriptors.js +283 -130
- package/dist/index.d.ts +25 -5
- package/dist/index.js +12 -2
- package/dist/keyExpressions.d.ts +54 -5
- package/dist/keyExpressions.js +30 -2
- package/dist/ledger.d.ts +89 -12
- package/dist/ledger.js +241 -28
- package/dist/scriptExpressions.d.ts +73 -28
- package/dist/scriptExpressions.js +26 -4
- package/dist/signers.d.ts +34 -1
- package/dist/signers.js +102 -41
- package/dist/types.d.ts +71 -39
- package/package.json +3 -2
package/dist/descriptors.js
CHANGED
|
@@ -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({
|
|
65
|
-
|
|
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 ${
|
|
68
|
-
//
|
|
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
|
|
73
|
+
let evaluatedDescriptor = descriptor;
|
|
71
74
|
if (mChecksum !== null) {
|
|
72
75
|
const checksum = mChecksum[0].substring(1); //remove the leading #
|
|
73
|
-
|
|
74
|
-
if (checksum !== (0, checksum_1.DescriptorChecksum)(
|
|
75
|
-
throw new Error(`Error: invalid descriptor checksum for ${
|
|
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 =
|
|
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()
|
|
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
|
-
|
|
91
|
+
evaluatedDescriptor = evaluatedDescriptor.replaceAll('*', index.toString());
|
|
89
92
|
}
|
|
90
93
|
else
|
|
91
|
-
throw new Error(`Error: index passed for non-ranged descriptor: ${
|
|
94
|
+
throw new Error(`Error: index passed for non-ranged descriptor: ${descriptor}`);
|
|
92
95
|
}
|
|
93
|
-
return
|
|
96
|
+
return evaluatedDescriptor;
|
|
94
97
|
}
|
|
95
98
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
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
|
|
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
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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
|
-
|
|
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({
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
__classPrivateFieldSet(this,
|
|
399
|
-
__classPrivateFieldSet(this,
|
|
400
|
-
if (typeof
|
|
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
|
-
|
|
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 ${
|
|
413
|
-
__classPrivateFieldSet(this,
|
|
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,
|
|
450
|
+
__classPrivateFieldSet(this, _Output_expandedExpression, expandedResult.expandedExpression, "f");
|
|
416
451
|
if (expandedResult.miniscript !== undefined)
|
|
417
|
-
__classPrivateFieldSet(this,
|
|
452
|
+
__classPrivateFieldSet(this, _Output_miniscript, expandedResult.miniscript, "f");
|
|
418
453
|
if (expandedResult.expansionMap !== undefined)
|
|
419
|
-
__classPrivateFieldSet(this,
|
|
454
|
+
__classPrivateFieldSet(this, _Output_expansionMap, expandedResult.expansionMap, "f");
|
|
420
455
|
if (expandedResult.isSegwit !== undefined)
|
|
421
|
-
__classPrivateFieldSet(this,
|
|
456
|
+
__classPrivateFieldSet(this, _Output_isSegwit, expandedResult.isSegwit, "f");
|
|
422
457
|
if (expandedResult.expandedMiniscript !== undefined)
|
|
423
|
-
__classPrivateFieldSet(this,
|
|
458
|
+
__classPrivateFieldSet(this, _Output_expandedMiniscript, expandedResult.expandedMiniscript, "f");
|
|
424
459
|
if (expandedResult.redeemScript !== undefined)
|
|
425
|
-
__classPrivateFieldSet(this,
|
|
460
|
+
__classPrivateFieldSet(this, _Output_redeemScript, expandedResult.redeemScript, "f");
|
|
426
461
|
if (expandedResult.witnessScript !== undefined)
|
|
427
|
-
__classPrivateFieldSet(this,
|
|
462
|
+
__classPrivateFieldSet(this, _Output_witnessScript, expandedResult.witnessScript, "f");
|
|
428
463
|
if (signersPubKeys) {
|
|
429
|
-
__classPrivateFieldSet(this,
|
|
464
|
+
__classPrivateFieldSet(this, _Output_signersPubKeys, signersPubKeys, "f");
|
|
430
465
|
}
|
|
431
466
|
else {
|
|
432
|
-
if (__classPrivateFieldGet(this,
|
|
433
|
-
__classPrivateFieldSet(this,
|
|
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 ${
|
|
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 ${
|
|
478
|
+
throw new Error(`Error: expansionMap not available for expression ${descriptor} that is not an address`);
|
|
444
479
|
}
|
|
445
|
-
__classPrivateFieldSet(this,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
505
|
+
return __classPrivateFieldGet(this, _Output_payment, "f").output;
|
|
464
506
|
}
|
|
465
507
|
/**
|
|
466
|
-
* Returns the compiled
|
|
467
|
-
*
|
|
468
|
-
*
|
|
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
|
-
|
|
471
|
-
const miniscript = __classPrivateFieldGet(this,
|
|
472
|
-
const expandedMiniscript = __classPrivateFieldGet(this,
|
|
473
|
-
const expansionMap = __classPrivateFieldGet(this,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
586
|
+
return __classPrivateFieldGet(this, _Output_network, "f");
|
|
514
587
|
}
|
|
588
|
+
/**
|
|
589
|
+
* Whether this `Output` is Segwit.
|
|
590
|
+
*/
|
|
515
591
|
isSegwit() {
|
|
516
|
-
return __classPrivateFieldGet(this,
|
|
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
|
-
*
|
|
520
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
579
|
-
if (!__classPrivateFieldGet(this,
|
|
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,
|
|
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,
|
|
591
|
-
? { expandedExpression: __classPrivateFieldGet(this,
|
|
723
|
+
...(__classPrivateFieldGet(this, _Output_expandedExpression, "f") !== undefined
|
|
724
|
+
? { expandedExpression: __classPrivateFieldGet(this, _Output_expandedExpression, "f") }
|
|
592
725
|
: {}),
|
|
593
|
-
...(__classPrivateFieldGet(this,
|
|
594
|
-
? { miniscript: __classPrivateFieldGet(this,
|
|
726
|
+
...(__classPrivateFieldGet(this, _Output_miniscript, "f") !== undefined
|
|
727
|
+
? { miniscript: __classPrivateFieldGet(this, _Output_miniscript, "f") }
|
|
595
728
|
: {}),
|
|
596
|
-
...(__classPrivateFieldGet(this,
|
|
597
|
-
? { expandedMiniscript: __classPrivateFieldGet(this,
|
|
729
|
+
...(__classPrivateFieldGet(this, _Output_expandedMiniscript, "f") !== undefined
|
|
730
|
+
? { expandedMiniscript: __classPrivateFieldGet(this, _Output_expandedMiniscript, "f") }
|
|
598
731
|
: {}),
|
|
599
|
-
...(__classPrivateFieldGet(this,
|
|
600
|
-
? { expansionMap: __classPrivateFieldGet(this,
|
|
732
|
+
...(__classPrivateFieldGet(this, _Output_expansionMap, "f") !== undefined
|
|
733
|
+
? { expansionMap: __classPrivateFieldGet(this, _Output_expansionMap, "f") }
|
|
601
734
|
: {})
|
|
602
735
|
};
|
|
603
736
|
}
|
|
604
737
|
}
|
|
605
|
-
|
|
606
|
-
const miniscript = __classPrivateFieldGet(this,
|
|
607
|
-
const preimages = __classPrivateFieldGet(this,
|
|
608
|
-
const expandedMiniscript = __classPrivateFieldGet(this,
|
|
609
|
-
const expansionMap = __classPrivateFieldGet(this,
|
|
610
|
-
const signersPubKeys = __classPrivateFieldGet(this,
|
|
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
|
-
},
|
|
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()
|
|
660
|
-
this.getRedeemScript()
|
|
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
|
-
|
|
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;
|