@bitcoinerlab/descriptors 2.0.2 → 2.1.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 +2 -2
- package/dist/descriptors.d.ts +89 -47
- package/dist/descriptors.js +290 -43
- package/dist/psbt.js +3 -26
- package/dist/types.d.ts +4 -2
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -73,11 +73,11 @@ const wpkhOutput = new Output({
|
|
|
73
73
|
});
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
For miniscript-based descriptors, the `signersPubKeys` parameter in the constuctor becomes particularly important. It specifies the spending path of a previous output with multiple spending paths. Detailed information about the constructor parameters, including `signersPubKeys`, can be found in [the API documentation](https://bitcoinerlab.com/modules/descriptors/api/classes/_Internal_.Output.html#constructor) and in [this Stack Exchange answer](https://bitcoin.stackexchange.com/a/118036/89665).
|
|
77
77
|
|
|
78
78
|
The `Output` class [offers various helpful methods](https://bitcoinerlab.com/modules/descriptors/api/classes/_Internal_.Output.html), including `getAddress()`, which returns the address associated with the descriptor, `getScriptPubKey()`, which returns the `scriptPubKey` for the descriptor, `expand()`, which decomposes a descriptor into its elemental parts, `updatePsbtAsInput()` and `updatePsbtAsOutput()`.
|
|
79
79
|
|
|
80
|
-
The `updatePsbtAsInput()` method is an essential part of the library, responsible for adding an input to the PSBT corresponding to the UTXO described by the descriptor. Additionally, when the descriptor expresses an absolute time-spending condition, such as "This UTXO can only be spent after block N,
|
|
80
|
+
The `updatePsbtAsInput()` method is an essential part of the library, responsible for adding an input to the PSBT corresponding to the UTXO described by the descriptor. Additionally, when the descriptor expresses an absolute time-spending condition, such as "This UTXO can only be spent after block N", `updatePsbtAsInput()` adds timelock information to the PSBT.
|
|
81
81
|
|
|
82
82
|
To call `updatePsbtAsInput()`, use the following syntax:
|
|
83
83
|
|
package/dist/descriptors.d.ts
CHANGED
|
@@ -66,23 +66,6 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
|
|
|
66
66
|
* satisfyMiniscript verifies that the time constraints did not change.
|
|
67
67
|
*/
|
|
68
68
|
"__#1@#getTimeConstraints"(): TimeConstraints | undefined;
|
|
69
|
-
/**
|
|
70
|
-
* Retrieves the byte length of the script satisfaction for a Miniscript-based
|
|
71
|
-
* descriptor, using only the expression, signers' public keys, and preimages
|
|
72
|
-
* provided in the constructor.
|
|
73
|
-
*
|
|
74
|
-
* Useful in scenarios like coin selection algorithms for transaction creation,
|
|
75
|
-
* where signatures are not yet available. Since signatures are still to be
|
|
76
|
-
* computed, the function assigns a standard length of 72 bytes for each
|
|
77
|
-
* signature. However, note that this may not always be completely accurate,
|
|
78
|
-
* as approximately 50% of signatures are 71 bytes in length
|
|
79
|
-
* (source: https://transactionfee.info/charts/bitcoin-script-ecdsa-length/).
|
|
80
|
-
* The function returns the byte length for a worst-case scenario.
|
|
81
|
-
*
|
|
82
|
-
* @returns The byte length of the compiled script satisfaction, or `undefined`
|
|
83
|
-
* if this was not a miniscript-based descriptor.
|
|
84
|
-
*/
|
|
85
|
-
getScriptSatisfactionSize(): number | undefined;
|
|
86
69
|
/**
|
|
87
70
|
* Creates and returns an instance of bitcoinjs-lib
|
|
88
71
|
* [`Payment`](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/payments/index.ts)'s interface with the `scriptPubKey` of this `Output`.
|
|
@@ -107,7 +90,7 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
|
|
|
107
90
|
* Important: As mentioned above, note that this function only applies to
|
|
108
91
|
* miniscript descriptors.
|
|
109
92
|
*/
|
|
110
|
-
getScriptSatisfaction(signatures: PartialSig[]): Buffer;
|
|
93
|
+
getScriptSatisfaction(signatures: PartialSig[] | 'DANGEROUSLY_USE_FAKE_SIGNATURES'): Buffer;
|
|
111
94
|
/**
|
|
112
95
|
* Gets the nSequence required to fulfill this `Output`.
|
|
113
96
|
*/
|
|
@@ -132,8 +115,40 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
|
|
|
132
115
|
getNetwork(): Network;
|
|
133
116
|
/**
|
|
134
117
|
* Whether this `Output` is Segwit.
|
|
118
|
+
*
|
|
119
|
+
* *NOTE:* When the descriptor in an input is `addr(address)`, it is assumed
|
|
120
|
+
* that any `addr(SH_TYPE_ADDRESS)` is in fact a Segwit `SH_WPKH`
|
|
121
|
+
* (Script Hash-Witness Public Key Hash).
|
|
122
|
+
* For inputs using arbitrary scripts (not standard addresses),
|
|
123
|
+
* use a descriptor in the format `sh(MINISCRIPT)`.
|
|
124
|
+
*
|
|
135
125
|
*/
|
|
136
126
|
isSegwit(): boolean | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* Returns the tuple: `{ isPKH: boolean; isWPKH: boolean; isSH: boolean; }`
|
|
129
|
+
* for this Output.
|
|
130
|
+
*/
|
|
131
|
+
guessOutput(): {
|
|
132
|
+
isPKH: boolean;
|
|
133
|
+
isWPKH: boolean;
|
|
134
|
+
isSH: boolean;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Computes the Weight Unit contributions of this Output as if it were the
|
|
138
|
+
* input in a tx.
|
|
139
|
+
*
|
|
140
|
+
* *NOTE:* When the descriptor in an input is `addr(address)`, it is assumed
|
|
141
|
+
* that any `addr(SH_TYPE_ADDRESS)` is in fact a Segwit `SH_WPKH`
|
|
142
|
+
* (Script Hash-Witness Public Key Hash).
|
|
143
|
+
* For inputs using arbitrary scripts (not standard addresses),
|
|
144
|
+
* use a descriptor in the format `sh(MINISCRIPT)`.
|
|
145
|
+
*/
|
|
146
|
+
inputWeight(isSegwitTx: boolean, signatures: PartialSig[] | 'DANGEROUSLY_USE_FAKE_SIGNATURES'): number;
|
|
147
|
+
/**
|
|
148
|
+
* Computes the Weight Unit contributions of this Output as if it were the
|
|
149
|
+
* output in a tx.
|
|
150
|
+
*/
|
|
151
|
+
outputWeight(): number;
|
|
137
152
|
/** @deprecated - Use updatePsbtAsInput instead
|
|
138
153
|
* @hidden
|
|
139
154
|
*/
|
|
@@ -274,22 +289,34 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
|
|
|
274
289
|
*/
|
|
275
290
|
network?: Network;
|
|
276
291
|
/**
|
|
277
|
-
* An array of preimages
|
|
292
|
+
* An array of preimages if the miniscript-based descriptor uses them.
|
|
293
|
+
*
|
|
294
|
+
* This info is necessary to finalize Psbts. Leave it `undefined` if your
|
|
295
|
+
* miniscript-based descriptor does not use preimages or you don't know
|
|
296
|
+
* or don't wanto use them.
|
|
297
|
+
*
|
|
298
|
+
* You can also leave it `undefined` if only need to generate the
|
|
299
|
+
* `scriptPubKey` or `address` for a descriptor.
|
|
300
|
+
*
|
|
278
301
|
* @defaultValue `[]`
|
|
279
302
|
*/
|
|
280
303
|
preimages?: Preimage[];
|
|
281
304
|
/**
|
|
282
305
|
* An array of the public keys used for signing the transaction when
|
|
283
|
-
* spending the output associated with this descriptor.
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
306
|
+
* spending the previous output associated with this descriptor.
|
|
307
|
+
*
|
|
308
|
+
* This parameter is only used if the descriptor object is being used to
|
|
309
|
+
* finalize a transaction. It is necessary to specify the spending path
|
|
310
|
+
* when working with miniscript-based expressions that have multiple
|
|
311
|
+
* spending paths.
|
|
312
|
+
*
|
|
313
|
+
* Set this parameter to an array containing the public
|
|
314
|
+
* keys involved in the desired spending path. Leave it `undefined` if you
|
|
315
|
+
* only need to generate the `scriptPubKey` or `address` for a descriptor,
|
|
316
|
+
* or if all the public keys involved in the descriptor will sign the
|
|
317
|
+
* transaction. In the latter case, the satisfier will automatically
|
|
318
|
+
* choose the most optimal spending path (if more than one is available).
|
|
319
|
+
*
|
|
293
320
|
* For more details on using this parameter, refer to [this Stack Exchange
|
|
294
321
|
* answer](https://bitcoin.stackexchange.com/a/118036/89665).
|
|
295
322
|
*/
|
|
@@ -321,23 +348,6 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
|
|
|
321
348
|
* satisfyMiniscript verifies that the time constraints did not change.
|
|
322
349
|
*/
|
|
323
350
|
"__#1@#getTimeConstraints"(): TimeConstraints | undefined;
|
|
324
|
-
/**
|
|
325
|
-
* Retrieves the byte length of the script satisfaction for a Miniscript-based
|
|
326
|
-
* descriptor, using only the expression, signers' public keys, and preimages
|
|
327
|
-
* provided in the constructor.
|
|
328
|
-
*
|
|
329
|
-
* Useful in scenarios like coin selection algorithms for transaction creation,
|
|
330
|
-
* where signatures are not yet available. Since signatures are still to be
|
|
331
|
-
* computed, the function assigns a standard length of 72 bytes for each
|
|
332
|
-
* signature. However, note that this may not always be completely accurate,
|
|
333
|
-
* as approximately 50% of signatures are 71 bytes in length
|
|
334
|
-
* (source: https://transactionfee.info/charts/bitcoin-script-ecdsa-length/).
|
|
335
|
-
* The function returns the byte length for a worst-case scenario.
|
|
336
|
-
*
|
|
337
|
-
* @returns The byte length of the compiled script satisfaction, or `undefined`
|
|
338
|
-
* if this was not a miniscript-based descriptor.
|
|
339
|
-
*/
|
|
340
|
-
getScriptSatisfactionSize(): number | undefined;
|
|
341
351
|
/**
|
|
342
352
|
* Creates and returns an instance of bitcoinjs-lib
|
|
343
353
|
* [`Payment`](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/payments/index.ts)'s interface with the `scriptPubKey` of this `Output`.
|
|
@@ -362,7 +372,7 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
|
|
|
362
372
|
* Important: As mentioned above, note that this function only applies to
|
|
363
373
|
* miniscript descriptors.
|
|
364
374
|
*/
|
|
365
|
-
getScriptSatisfaction(signatures: PartialSig[]): Buffer;
|
|
375
|
+
getScriptSatisfaction(signatures: PartialSig[] | 'DANGEROUSLY_USE_FAKE_SIGNATURES'): Buffer;
|
|
366
376
|
/**
|
|
367
377
|
* Gets the nSequence required to fulfill this `Output`.
|
|
368
378
|
*/
|
|
@@ -387,8 +397,40 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
|
|
|
387
397
|
getNetwork(): Network;
|
|
388
398
|
/**
|
|
389
399
|
* Whether this `Output` is Segwit.
|
|
400
|
+
*
|
|
401
|
+
* *NOTE:* When the descriptor in an input is `addr(address)`, it is assumed
|
|
402
|
+
* that any `addr(SH_TYPE_ADDRESS)` is in fact a Segwit `SH_WPKH`
|
|
403
|
+
* (Script Hash-Witness Public Key Hash).
|
|
404
|
+
* For inputs using arbitrary scripts (not standard addresses),
|
|
405
|
+
* use a descriptor in the format `sh(MINISCRIPT)`.
|
|
406
|
+
*
|
|
390
407
|
*/
|
|
391
408
|
isSegwit(): boolean | undefined;
|
|
409
|
+
/**
|
|
410
|
+
* Returns the tuple: `{ isPKH: boolean; isWPKH: boolean; isSH: boolean; }`
|
|
411
|
+
* for this Output.
|
|
412
|
+
*/
|
|
413
|
+
guessOutput(): {
|
|
414
|
+
isPKH: boolean;
|
|
415
|
+
isWPKH: boolean;
|
|
416
|
+
isSH: boolean;
|
|
417
|
+
};
|
|
418
|
+
/**
|
|
419
|
+
* Computes the Weight Unit contributions of this Output as if it were the
|
|
420
|
+
* input in a tx.
|
|
421
|
+
*
|
|
422
|
+
* *NOTE:* When the descriptor in an input is `addr(address)`, it is assumed
|
|
423
|
+
* that any `addr(SH_TYPE_ADDRESS)` is in fact a Segwit `SH_WPKH`
|
|
424
|
+
* (Script Hash-Witness Public Key Hash).
|
|
425
|
+
* For inputs using arbitrary scripts (not standard addresses),
|
|
426
|
+
* use a descriptor in the format `sh(MINISCRIPT)`.
|
|
427
|
+
*/
|
|
428
|
+
inputWeight(isSegwitTx: boolean, signatures: PartialSig[] | 'DANGEROUSLY_USE_FAKE_SIGNATURES'): number;
|
|
429
|
+
/**
|
|
430
|
+
* Computes the Weight Unit contributions of this Output as if it were the
|
|
431
|
+
* output in a tx.
|
|
432
|
+
*/
|
|
433
|
+
outputWeight(): number;
|
|
392
434
|
/** @deprecated - Use updatePsbtAsInput instead
|
|
393
435
|
* @hidden
|
|
394
436
|
*/
|
package/dist/descriptors.js
CHANGED
|
@@ -35,9 +35,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
35
35
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
36
36
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
37
37
|
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
38
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
42
|
exports.DescriptorsFactory = void 0;
|
|
43
|
+
const lodash_memoize_1 = __importDefault(require("lodash.memoize"));
|
|
40
44
|
const bitcoinjs_lib_1 = require("bitcoinjs-lib");
|
|
45
|
+
const varuint_bitcoin_1 = require("varuint-bitcoin");
|
|
41
46
|
const { p2sh, p2wpkh, p2pkh, p2pk, p2wsh, p2tr } = bitcoinjs_lib_1.payments;
|
|
42
47
|
const bip32_1 = require("bip32");
|
|
43
48
|
const ecpair_1 = require("ecpair");
|
|
@@ -57,6 +62,28 @@ function countNonPushOnlyOPs(script) {
|
|
|
57
62
|
throw new Error(`Error: cound not decompile ${script}`);
|
|
58
63
|
return decompile.filter(op => typeof op === 'number' && op > bitcoinjs_lib_1.script.OPS['OP_16']).length;
|
|
59
64
|
}
|
|
65
|
+
function vectorSize(someVector) {
|
|
66
|
+
const length = someVector.length;
|
|
67
|
+
return ((0, varuint_bitcoin_1.encodingLength)(length) +
|
|
68
|
+
someVector.reduce((sum, witness) => {
|
|
69
|
+
return sum + varSliceSize(witness);
|
|
70
|
+
}, 0));
|
|
71
|
+
}
|
|
72
|
+
function varSliceSize(someScript) {
|
|
73
|
+
const length = someScript.length;
|
|
74
|
+
return (0, varuint_bitcoin_1.encodingLength)(length) + length;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* This function will typically return 73; since it assumes a signature size of
|
|
78
|
+
* 72 bytes (this is the max size of a DER encoded signature) and it adds 1
|
|
79
|
+
* extra byte for encoding its length
|
|
80
|
+
*/
|
|
81
|
+
function signatureSize(signature) {
|
|
82
|
+
const length = signature === 'DANGEROUSLY_USE_FAKE_SIGNATURES'
|
|
83
|
+
? 72
|
|
84
|
+
: signature.signature.length;
|
|
85
|
+
return (0, varuint_bitcoin_1.encodingLength)(length) + length;
|
|
86
|
+
}
|
|
60
87
|
/*
|
|
61
88
|
* Returns a bare descriptor without checksum and particularized for a certain
|
|
62
89
|
* index (if desc was a range descriptor)
|
|
@@ -184,22 +211,28 @@ function DescriptorsFactory(ecc) {
|
|
|
184
211
|
}
|
|
185
212
|
try {
|
|
186
213
|
payment = p2pkh({ output, network });
|
|
214
|
+
isSegwit = false;
|
|
187
215
|
}
|
|
188
216
|
catch (e) { }
|
|
189
217
|
try {
|
|
190
218
|
payment = p2sh({ output, network });
|
|
219
|
+
// It assumes that an addr(SH_ADDRESS) is always a add(SH_WPKH) address
|
|
220
|
+
isSegwit = true;
|
|
191
221
|
}
|
|
192
222
|
catch (e) { }
|
|
193
223
|
try {
|
|
194
224
|
payment = p2wpkh({ output, network });
|
|
225
|
+
isSegwit = true;
|
|
195
226
|
}
|
|
196
227
|
catch (e) { }
|
|
197
228
|
try {
|
|
198
229
|
payment = p2wsh({ output, network });
|
|
230
|
+
isSegwit = true;
|
|
199
231
|
}
|
|
200
232
|
catch (e) { }
|
|
201
233
|
try {
|
|
202
234
|
payment = p2tr({ output, network });
|
|
235
|
+
isSegwit = true;
|
|
203
236
|
}
|
|
204
237
|
catch (e) { }
|
|
205
238
|
if (!payment) {
|
|
@@ -480,49 +513,25 @@ function DescriptorsFactory(ecc) {
|
|
|
480
513
|
__classPrivateFieldSet(this, _Output_signersPubKeys, [this.getScriptPubKey()], "f");
|
|
481
514
|
}
|
|
482
515
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
const preimages = __classPrivateFieldGet(this, _Output_preimages, "f");
|
|
503
|
-
const expandedMiniscript = __classPrivateFieldGet(this, _Output_expandedMiniscript, "f");
|
|
504
|
-
const expansionMap = __classPrivateFieldGet(this, _Output_expansionMap, "f");
|
|
505
|
-
const signersPubKeys = __classPrivateFieldGet(this, _Output_signersPubKeys, "f");
|
|
506
|
-
//Create a method. solvePreimages to solve them.
|
|
507
|
-
if (miniscript) {
|
|
508
|
-
if (expandedMiniscript === undefined || expansionMap === undefined)
|
|
509
|
-
throw new Error(`Error: cannot get script satisfactions from not expanded miniscript ${miniscript}`);
|
|
510
|
-
//We create some fakeSignatures since we may not have them yet.
|
|
511
|
-
const fakeSignatures = signersPubKeys.map(pubkey => ({
|
|
512
|
-
pubkey,
|
|
513
|
-
// https://transactionfee.info/charts/bitcoin-script-ecdsa-length/
|
|
514
|
-
signature: Buffer.alloc(72, 0)
|
|
515
|
-
}));
|
|
516
|
-
const { scriptSatisfaction } = (0, miniscript_1.satisfyMiniscript)({
|
|
517
|
-
expandedMiniscript,
|
|
518
|
-
expansionMap,
|
|
519
|
-
signatures: fakeSignatures,
|
|
520
|
-
preimages
|
|
521
|
-
});
|
|
522
|
-
return scriptSatisfaction.length;
|
|
523
|
-
}
|
|
524
|
-
else
|
|
525
|
-
return undefined;
|
|
516
|
+
this.getSequence = (0, lodash_memoize_1.default)(this.getSequence);
|
|
517
|
+
this.getLockTime = (0, lodash_memoize_1.default)(this.getLockTime);
|
|
518
|
+
const getSignaturesKey = (signatures) => signatures === 'DANGEROUSLY_USE_FAKE_SIGNATURES'
|
|
519
|
+
? signatures
|
|
520
|
+
: signatures
|
|
521
|
+
.map(s => `${s.pubkey.toString('hex')}-${s.signature.toString('hex')}`)
|
|
522
|
+
.join('|');
|
|
523
|
+
this.getScriptSatisfaction = (0, lodash_memoize_1.default)(this.getScriptSatisfaction,
|
|
524
|
+
// resolver function:
|
|
525
|
+
getSignaturesKey);
|
|
526
|
+
this.guessOutput = (0, lodash_memoize_1.default)(this.guessOutput);
|
|
527
|
+
this.inputWeight = (0, lodash_memoize_1.default)(this.inputWeight,
|
|
528
|
+
// resolver function:
|
|
529
|
+
(isSegwitTx, signatures) => {
|
|
530
|
+
const segwitKey = isSegwitTx ? 'segwit' : 'non-segwit';
|
|
531
|
+
const signaturesKey = getSignaturesKey(signatures);
|
|
532
|
+
return `${segwitKey}-${signaturesKey}`;
|
|
533
|
+
});
|
|
534
|
+
this.outputWeight = (0, lodash_memoize_1.default)(this.outputWeight);
|
|
526
535
|
}
|
|
527
536
|
/**
|
|
528
537
|
* Creates and returns an instance of bitcoinjs-lib
|
|
@@ -565,8 +574,28 @@ function DescriptorsFactory(ecc) {
|
|
|
565
574
|
*
|
|
566
575
|
* `signatures` must be passed using this format (pairs of `pubKey/signature`):
|
|
567
576
|
* `interface PartialSig { pubkey: Buffer; signature: Buffer; }`
|
|
577
|
+
*
|
|
578
|
+
* * Alternatively, if you do not have the signatures, you can use the option
|
|
579
|
+
* `'DANGEROUSLY_USE_FAKE_SIGNATURES'`. This will generate script satisfactions
|
|
580
|
+
* using 72-byte zero-padded signatures. While this can be useful in
|
|
581
|
+
* modules like coinselector that require estimating transaction size before
|
|
582
|
+
* signing, it is critical to understand the risks:
|
|
583
|
+
* - Using this option generales invalid unlocking scripts.
|
|
584
|
+
* - It should NEVER be used with real transactions.
|
|
585
|
+
* - Its primary use is for testing and size estimation purposes only.
|
|
586
|
+
*
|
|
587
|
+
* ⚠️ Warning: Misuse of 'DANGEROUSLY_USE_FAKE_SIGNATURES' can lead to security
|
|
588
|
+
* vulnerabilities, including but not limited to invalid transaction generation.
|
|
589
|
+
* Ensure you fully understand the implications before use.
|
|
590
|
+
*
|
|
568
591
|
*/
|
|
569
592
|
signatures) {
|
|
593
|
+
if (signatures === 'DANGEROUSLY_USE_FAKE_SIGNATURES')
|
|
594
|
+
signatures = __classPrivateFieldGet(this, _Output_signersPubKeys, "f").map(pubkey => ({
|
|
595
|
+
pubkey,
|
|
596
|
+
// https://transactionfee.info/charts/bitcoin-script-ecdsa-length/
|
|
597
|
+
signature: Buffer.alloc(72, 0)
|
|
598
|
+
}));
|
|
570
599
|
const miniscript = __classPrivateFieldGet(this, _Output_miniscript, "f");
|
|
571
600
|
const expandedMiniscript = __classPrivateFieldGet(this, _Output_expandedMiniscript, "f");
|
|
572
601
|
const expansionMap = __classPrivateFieldGet(this, _Output_expansionMap, "f");
|
|
@@ -630,10 +659,228 @@ function DescriptorsFactory(ecc) {
|
|
|
630
659
|
}
|
|
631
660
|
/**
|
|
632
661
|
* Whether this `Output` is Segwit.
|
|
662
|
+
*
|
|
663
|
+
* *NOTE:* When the descriptor in an input is `addr(address)`, it is assumed
|
|
664
|
+
* that any `addr(SH_TYPE_ADDRESS)` is in fact a Segwit `SH_WPKH`
|
|
665
|
+
* (Script Hash-Witness Public Key Hash).
|
|
666
|
+
* For inputs using arbitrary scripts (not standard addresses),
|
|
667
|
+
* use a descriptor in the format `sh(MINISCRIPT)`.
|
|
668
|
+
*
|
|
633
669
|
*/
|
|
634
670
|
isSegwit() {
|
|
635
671
|
return __classPrivateFieldGet(this, _Output_isSegwit, "f");
|
|
636
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Returns the tuple: `{ isPKH: boolean; isWPKH: boolean; isSH: boolean; }`
|
|
675
|
+
* for this Output.
|
|
676
|
+
*/
|
|
677
|
+
guessOutput() {
|
|
678
|
+
function guessSH(output) {
|
|
679
|
+
try {
|
|
680
|
+
bitcoinjs_lib_1.payments.p2sh({ output });
|
|
681
|
+
return true;
|
|
682
|
+
}
|
|
683
|
+
catch (err) {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
function guessWPKH(output) {
|
|
688
|
+
try {
|
|
689
|
+
bitcoinjs_lib_1.payments.p2wpkh({ output });
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
692
|
+
catch (err) {
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
function guessPKH(output) {
|
|
697
|
+
try {
|
|
698
|
+
bitcoinjs_lib_1.payments.p2pkh({ output });
|
|
699
|
+
return true;
|
|
700
|
+
}
|
|
701
|
+
catch (err) {
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
const isPKH = guessPKH(this.getScriptPubKey());
|
|
706
|
+
const isWPKH = guessWPKH(this.getScriptPubKey());
|
|
707
|
+
const isSH = guessSH(this.getScriptPubKey());
|
|
708
|
+
if ([isPKH, isWPKH, isSH].filter(Boolean).length > 1)
|
|
709
|
+
throw new Error('Cannot have multiple output types.');
|
|
710
|
+
return { isPKH, isWPKH, isSH };
|
|
711
|
+
}
|
|
712
|
+
// References for inputWeight & outputWeight:
|
|
713
|
+
// https://gist.github.com/junderw/b43af3253ea5865ed52cb51c200ac19c
|
|
714
|
+
// https://bitcoinops.org/en/tools/calc-size/
|
|
715
|
+
// Look for byteLength: https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/transaction.ts
|
|
716
|
+
// https://github.com/bitcoinjs/coinselect/blob/master/utils.js
|
|
717
|
+
/**
|
|
718
|
+
* Computes the Weight Unit contributions of this Output as if it were the
|
|
719
|
+
* input in a tx.
|
|
720
|
+
*
|
|
721
|
+
* *NOTE:* When the descriptor in an input is `addr(address)`, it is assumed
|
|
722
|
+
* that any `addr(SH_TYPE_ADDRESS)` is in fact a Segwit `SH_WPKH`
|
|
723
|
+
* (Script Hash-Witness Public Key Hash).
|
|
724
|
+
* For inputs using arbitrary scripts (not standard addresses),
|
|
725
|
+
* use a descriptor in the format `sh(MINISCRIPT)`.
|
|
726
|
+
*/
|
|
727
|
+
inputWeight(
|
|
728
|
+
/**
|
|
729
|
+
* Indicates if the transaction is a Segwit transaction.
|
|
730
|
+
* If a transaction isSegwitTx, a single byte is then also required for
|
|
731
|
+
* non-witness inputs to encode the length of the empty witness stack:
|
|
732
|
+
* encodeLength(0) + 0 = 1
|
|
733
|
+
* Read more:
|
|
734
|
+
* https://gist.github.com/junderw/b43af3253ea5865ed52cb51c200ac19c?permalink_comment_id=4760512#gistcomment-4760512
|
|
735
|
+
*/
|
|
736
|
+
isSegwitTx,
|
|
737
|
+
/*
|
|
738
|
+
* Array of `PartialSig`. Each `PartialSig` includes
|
|
739
|
+
* a public key and its corresponding signature. This parameter
|
|
740
|
+
* enables the accurate calculation of signature sizes.
|
|
741
|
+
* Pass 'DANGEROUSLY_USE_FAKE_SIGNATURES' to assume 72 bytes in length.
|
|
742
|
+
* Mainly used for testing.
|
|
743
|
+
*/
|
|
744
|
+
signatures) {
|
|
745
|
+
if (this.isSegwit() && !isSegwitTx)
|
|
746
|
+
throw new Error(`a tx is segwit if at least one input is segwit`);
|
|
747
|
+
const errorMsg = 'Input type not implemented. Currently supported: pkh(KEY), wpkh(KEY), \
|
|
748
|
+
sh(wpkh(KEY)), sh(wsh(MINISCRIPT)), sh(MINISCRIPT), wsh(MINISCRIPT), \
|
|
749
|
+
addr(PKH_ADDRESS), addr(WPKH_ADDRESS), addr(SH_WPKH_ADDRESS).';
|
|
750
|
+
//expand any miniscript-based descriptor. If not miniscript-based, then it's
|
|
751
|
+
//an addr() descriptor. For those, we can only guess their type.
|
|
752
|
+
const expansion = this.expand().expandedExpression;
|
|
753
|
+
const { isPKH, isWPKH, isSH } = this.guessOutput();
|
|
754
|
+
if (!expansion && !isPKH && !isWPKH && !isSH)
|
|
755
|
+
throw new Error(errorMsg);
|
|
756
|
+
const firstSignature = signatures && typeof signatures[0] === 'object'
|
|
757
|
+
? signatures[0]
|
|
758
|
+
: 'DANGEROUSLY_USE_FAKE_SIGNATURES';
|
|
759
|
+
if (expansion ? expansion.startsWith('pkh(') : isPKH) {
|
|
760
|
+
return (
|
|
761
|
+
// Non-segwit: (txid:32) + (vout:4) + (sequence:4) + (script_len:1) + (sig:73) + (pubkey:34)
|
|
762
|
+
(32 + 4 + 4 + 1 + signatureSize(firstSignature) + 34) * 4 +
|
|
763
|
+
//Segwit:
|
|
764
|
+
(isSegwitTx ? 1 : 0));
|
|
765
|
+
}
|
|
766
|
+
else if (expansion ? expansion.startsWith('wpkh(') : isWPKH) {
|
|
767
|
+
if (!isSegwitTx)
|
|
768
|
+
throw new Error('Should be SegwitTx');
|
|
769
|
+
return (
|
|
770
|
+
// Non-segwit: (txid:32) + (vout:4) + (sequence:4) + (script_len:1)
|
|
771
|
+
41 * 4 +
|
|
772
|
+
// Segwit: (push_count:1) + (sig:73) + (pubkey:34)
|
|
773
|
+
(1 + signatureSize(firstSignature) + 34));
|
|
774
|
+
}
|
|
775
|
+
else if (expansion ? expansion.startsWith('sh(wpkh(') : isSH) {
|
|
776
|
+
if (!isSegwitTx)
|
|
777
|
+
throw new Error('Should be SegwitTx');
|
|
778
|
+
return (
|
|
779
|
+
// Non-segwit: (txid:32) + (vout:4) + (sequence:4) + (script_len:1) + (p2wpkh:23)
|
|
780
|
+
// -> p2wpkh_script: OP_0 OP_PUSH20 <public_key_hash>
|
|
781
|
+
// -> p2wpkh: (script_len:1) + (script:22)
|
|
782
|
+
64 * 4 +
|
|
783
|
+
// Segwit: (push_count:1) + (sig:73) + (pubkey:34)
|
|
784
|
+
(1 + signatureSize(firstSignature) + 34));
|
|
785
|
+
}
|
|
786
|
+
else if (expansion?.startsWith('sh(wsh(')) {
|
|
787
|
+
if (!isSegwitTx)
|
|
788
|
+
throw new Error('Should be SegwitTx');
|
|
789
|
+
const witnessScript = this.getWitnessScript();
|
|
790
|
+
if (!witnessScript)
|
|
791
|
+
throw new Error('sh(wsh) must provide witnessScript');
|
|
792
|
+
const payment = bitcoinjs_lib_1.payments.p2sh({
|
|
793
|
+
redeem: bitcoinjs_lib_1.payments.p2wsh({
|
|
794
|
+
redeem: {
|
|
795
|
+
input: this.getScriptSatisfaction(signatures || 'DANGEROUSLY_USE_FAKE_SIGNATURES'),
|
|
796
|
+
output: witnessScript
|
|
797
|
+
}
|
|
798
|
+
})
|
|
799
|
+
});
|
|
800
|
+
if (!payment || !payment.input || !payment.witness)
|
|
801
|
+
throw new Error('Could not create payment');
|
|
802
|
+
return (
|
|
803
|
+
//Non-segwit
|
|
804
|
+
4 * (40 + varSliceSize(payment.input)) +
|
|
805
|
+
//Segwit
|
|
806
|
+
vectorSize(payment.witness));
|
|
807
|
+
}
|
|
808
|
+
else if (expansion?.startsWith('sh(')) {
|
|
809
|
+
const redeemScript = this.getRedeemScript();
|
|
810
|
+
if (!redeemScript)
|
|
811
|
+
throw new Error('sh() must provide redeemScript');
|
|
812
|
+
const payment = bitcoinjs_lib_1.payments.p2sh({
|
|
813
|
+
redeem: {
|
|
814
|
+
input: this.getScriptSatisfaction(signatures || 'DANGEROUSLY_USE_FAKE_SIGNATURES'),
|
|
815
|
+
output: redeemScript
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
if (!payment || !payment.input)
|
|
819
|
+
throw new Error('Could not create payment');
|
|
820
|
+
if (payment.witness?.length)
|
|
821
|
+
throw new Error('A legacy p2sh payment should not cointain a witness');
|
|
822
|
+
return (
|
|
823
|
+
//Non-segwit
|
|
824
|
+
4 * (40 + varSliceSize(payment.input)) +
|
|
825
|
+
//Segwit:
|
|
826
|
+
(isSegwitTx ? 1 : 0));
|
|
827
|
+
}
|
|
828
|
+
else if (expansion?.startsWith('wsh(')) {
|
|
829
|
+
const witnessScript = this.getWitnessScript();
|
|
830
|
+
if (!witnessScript)
|
|
831
|
+
throw new Error('wsh must provide witnessScript');
|
|
832
|
+
const payment = bitcoinjs_lib_1.payments.p2wsh({
|
|
833
|
+
redeem: {
|
|
834
|
+
input: this.getScriptSatisfaction(signatures || 'DANGEROUSLY_USE_FAKE_SIGNATURES'),
|
|
835
|
+
output: witnessScript
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
if (!payment || !payment.input || !payment.witness)
|
|
839
|
+
throw new Error('Could not create payment');
|
|
840
|
+
return (
|
|
841
|
+
//Non-segwit
|
|
842
|
+
4 * (40 + varSliceSize(payment.input)) +
|
|
843
|
+
//Segwit
|
|
844
|
+
vectorSize(payment.witness));
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
throw new Error(errorMsg);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Computes the Weight Unit contributions of this Output as if it were the
|
|
852
|
+
* output in a tx.
|
|
853
|
+
*/
|
|
854
|
+
outputWeight() {
|
|
855
|
+
const errorMsg = 'Output type not implemented. Currently supported: pkh(KEY), wpkh(KEY), \
|
|
856
|
+
sh(ANYTHING), wsh(ANYTHING), addr(PKH_ADDRESS), addr(WPKH_ADDRESS), \
|
|
857
|
+
addr(SH_WPKH_ADDRESS)';
|
|
858
|
+
//expand any miniscript-based descriptor. If not miniscript-based, then it's
|
|
859
|
+
//an addr() descriptor. For those, we can only guess their type.
|
|
860
|
+
const expansion = this.expand().expandedExpression;
|
|
861
|
+
const { isPKH, isWPKH, isSH } = this.guessOutput();
|
|
862
|
+
if (!expansion && !isPKH && !isWPKH && !isSH)
|
|
863
|
+
throw new Error(errorMsg);
|
|
864
|
+
if (expansion ? expansion.startsWith('pkh(') : isPKH) {
|
|
865
|
+
// (p2pkh:26) + (amount:8)
|
|
866
|
+
return 34 * 4;
|
|
867
|
+
}
|
|
868
|
+
else if (expansion ? expansion.startsWith('wpkh(') : isWPKH) {
|
|
869
|
+
// (p2wpkh:23) + (amount:8)
|
|
870
|
+
return 31 * 4;
|
|
871
|
+
}
|
|
872
|
+
else if (expansion ? expansion.startsWith('sh(') : isSH) {
|
|
873
|
+
// (p2sh:24) + (amount:8)
|
|
874
|
+
return 32 * 4;
|
|
875
|
+
}
|
|
876
|
+
else if (expansion?.startsWith('wsh(')) {
|
|
877
|
+
// (p2wsh:35) + (amount:8)
|
|
878
|
+
return 43 * 4;
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
throw new Error(errorMsg);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
637
884
|
/** @deprecated - Use updatePsbtAsInput instead
|
|
638
885
|
* @hidden
|
|
639
886
|
*/
|
package/dist/psbt.js
CHANGED
|
@@ -1,33 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Copyright (c) 2023 Jose-Luis Landabaso - https://bitcoinerlab.com
|
|
3
3
|
// Distributed under the MIT software license
|
|
4
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
-
if (k2 === undefined) k2 = k;
|
|
6
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
-
}
|
|
10
|
-
Object.defineProperty(o, k2, desc);
|
|
11
|
-
}) : (function(o, m, k, k2) {
|
|
12
|
-
if (k2 === undefined) k2 = k;
|
|
13
|
-
o[k2] = m[k];
|
|
14
|
-
}));
|
|
15
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
-
}) : function(o, v) {
|
|
18
|
-
o["default"] = v;
|
|
19
|
-
});
|
|
20
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
21
|
-
if (mod && mod.__esModule) return mod;
|
|
22
|
-
var result = {};
|
|
23
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
24
|
-
__setModuleDefault(result, mod);
|
|
25
|
-
return result;
|
|
26
|
-
};
|
|
27
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
5
|
exports.updatePsbt = exports.finalScriptsFuncFactory = void 0;
|
|
29
6
|
const bitcoinjs_lib_1 = require("bitcoinjs-lib");
|
|
30
|
-
const
|
|
7
|
+
const varuint_bitcoin_1 = require("varuint-bitcoin");
|
|
31
8
|
function reverseBuffer(buffer) {
|
|
32
9
|
if (buffer.length < 1)
|
|
33
10
|
return buffer;
|
|
@@ -48,9 +25,9 @@ function witnessStackToScriptWitness(witness) {
|
|
|
48
25
|
}
|
|
49
26
|
function writeVarInt(i) {
|
|
50
27
|
const currentLen = buffer.length;
|
|
51
|
-
const varintLen =
|
|
28
|
+
const varintLen = (0, varuint_bitcoin_1.encodingLength)(i);
|
|
52
29
|
buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
|
|
53
|
-
|
|
30
|
+
(0, varuint_bitcoin_1.encode)(i, buffer, currentLen);
|
|
54
31
|
}
|
|
55
32
|
function writeVarSlice(slice) {
|
|
56
33
|
writeVarInt(slice.length);
|
package/dist/types.d.ts
CHANGED
|
@@ -9,13 +9,15 @@ import type { Payment, Network } from 'bitcoinjs-lib';
|
|
|
9
9
|
*/
|
|
10
10
|
export type Preimage = {
|
|
11
11
|
/**
|
|
12
|
-
* Use same expressions as in miniscript. For example: "sha256(cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)" or "ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e)"
|
|
12
|
+
* Use same string expressions as in miniscript. For example: "sha256(cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204)" or "ripemd160(095ff41131e5946f3c85f79e44adbcf8e27e080e)"
|
|
13
|
+
*
|
|
13
14
|
* Accepted functions: sha256, hash256, ripemd160, hash160
|
|
15
|
+
*
|
|
14
16
|
* Digests must be: 64-character HEX for sha256, hash160 or 30-character HEX for ripemd160 or hash160.
|
|
15
17
|
*/
|
|
16
18
|
digest: string;
|
|
17
19
|
/**
|
|
18
|
-
* Hex encoded
|
|
20
|
+
* Hex encoded preimage. Preimages are always 32 bytes (so, 64 character in hex).
|
|
19
21
|
*/
|
|
20
22
|
preimage: string;
|
|
21
23
|
};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@bitcoinerlab/descriptors",
|
|
3
3
|
"description": "This library parses and creates Bitcoin Miniscript Descriptors and generates Partially Signed Bitcoin Transactions (PSBTs). It provides PSBT finalizers and signers for single-signature, BIP32 and Hardware Wallets.",
|
|
4
4
|
"homepage": "https://github.com/bitcoinerlab/descriptors",
|
|
5
|
-
"version": "2.0
|
|
5
|
+
"version": "2.1.0",
|
|
6
6
|
"author": "Jose-Luis Landabaso",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"docs": "typedoc --options ./node_modules/@bitcoinerlab/configs/typedoc.json",
|
|
33
33
|
"build:src": "tsc --project ./node_modules/@bitcoinerlab/configs/tsconfig.src.json",
|
|
34
34
|
"build:fixtures": "node test/tools/generateBitcoinCoreFixtures.js -i test/fixtures/descriptor_tests.cpp | npx prettier --parser typescript > test/fixtures/bitcoinCore.ts",
|
|
35
|
-
"build:test": "npm run build:fixtures && tsc --project ./node_modules/@bitcoinerlab/configs/tsconfig.test.json",
|
|
35
|
+
"build:test": "npm run build:fixtures && tsc --project ./node_modules/@bitcoinerlab/configs/tsconfig.test.json --resolveJsonModule",
|
|
36
36
|
"build": "npm run build:src && npm run build:test",
|
|
37
37
|
"lint": "eslint --ignore-path .gitignore --ext .ts src/ test/",
|
|
38
38
|
"ensureTester": "./node_modules/@bitcoinerlab/configs/scripts/ensureTester.sh",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@bitcoinerlab/configs": "github:bitcoinerlab/configs",
|
|
60
60
|
"@ledgerhq/hw-transport-node-hid": "^6.27.12",
|
|
61
|
+
"@types/lodash.memoize": "^4.1.9",
|
|
61
62
|
"bip39": "^3.0.4",
|
|
62
63
|
"bip65": "^1.0.3",
|
|
63
64
|
"bip68": "^1.0.4",
|
|
@@ -70,6 +71,8 @@
|
|
|
70
71
|
"@bitcoinerlab/secp256k1": "^1.0.5",
|
|
71
72
|
"bip32": "^4.0.0",
|
|
72
73
|
"bitcoinjs-lib": "^6.1.3",
|
|
73
|
-
"ecpair": "^2.1.0"
|
|
74
|
+
"ecpair": "^2.1.0",
|
|
75
|
+
"lodash.memoize": "^4.1.2",
|
|
76
|
+
"varuint-bitcoin": "^1.1.2"
|
|
74
77
|
}
|
|
75
78
|
}
|