@bitcoinerlab/descriptors 0.2.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.
@@ -0,0 +1,627 @@
1
+ "use strict";
2
+ // Copyright (c) 2023 Jose-Luis Landabaso - https://bitcoinerlab.com
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
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
28
+ if (kind === "m") throw new TypeError("Private method is not writable");
29
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
30
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
31
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
32
+ };
33
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
34
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
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
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.DescriptorsFactory = void 0;
40
+ const bitcoinjs_lib_1 = require("bitcoinjs-lib");
41
+ const { p2sh, p2wpkh, p2pkh, p2pk, p2wsh, p2tr } = bitcoinjs_lib_1.payments;
42
+ const bip32_1 = require("bip32");
43
+ const ecpair_1 = require("ecpair");
44
+ const psbt_1 = require("./psbt");
45
+ const checksum_1 = require("./checksum");
46
+ const keyExpressions_1 = require("./keyExpressions");
47
+ const RE = __importStar(require("./re"));
48
+ const miniscript_1 = require("./miniscript");
49
+ //See "Resource limitations" https://bitcoin.sipa.be/miniscript/
50
+ //https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-September/017306.html
51
+ const MAX_SCRIPT_ELEMENT_SIZE = 520;
52
+ const MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
53
+ const MAX_OPS_PER_SCRIPT = 201;
54
+ function countNonPushOnlyOPs(script) {
55
+ const decompile = bitcoinjs_lib_1.script.decompile(script);
56
+ if (!decompile)
57
+ throw new Error(`Error: cound not decompile ${script}`);
58
+ return decompile.filter(op => op > bitcoinjs_lib_1.script.OPS['OP_16']).length;
59
+ }
60
+ /*
61
+ * Returns a bare descriptor without checksum and particularized for a certain
62
+ * index (if desc was a range descriptor)
63
+ */
64
+ function evaluate({ expression, checksumRequired, index }) {
65
+ const mChecksum = expression.match(String.raw `(${RE.reChecksum})$`);
66
+ if (mChecksum === null && checksumRequired === true)
67
+ throw new Error(`Error: descriptor ${expression} has not checksum`);
68
+ //evaluatedExpression: a bare desc without checksum and particularized for a certain
69
+ //index (if desc was a range descriptor)
70
+ let evaluatedExpression = expression;
71
+ if (mChecksum !== null) {
72
+ const checksum = mChecksum[0].substring(1); //remove the leading #
73
+ evaluatedExpression = expression.substring(0, expression.length - mChecksum[0].length);
74
+ if (checksum !== (0, checksum_1.DescriptorChecksum)(evaluatedExpression)) {
75
+ throw new Error(`Error: invalid descriptor checksum for ${expression}`);
76
+ }
77
+ }
78
+ const mWildcard = evaluatedExpression.match(/\*/g);
79
+ if (mWildcard && mWildcard.length > 0) {
80
+ if (index === undefined)
81
+ throw new Error(`Error: index was not provided for ranged descriptor`);
82
+ if (!Number.isInteger(index) || index < 0)
83
+ throw new Error(`Error: invalid index ${index}`);
84
+ //From https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md
85
+ //To prevent a combinatorial explosion of the search space, if more than
86
+ //one of the multi() key arguments is a BIP32 wildcard path ending in /* or
87
+ //*', the multi() expression only matches multisig scripts with the ith
88
+ //child key from each wildcard path in lockstep, rather than scripts with
89
+ //any combination of child keys from each wildcard path.
90
+ //We extend this reasoning for musig for all cases
91
+ evaluatedExpression = evaluatedExpression.replaceAll('*', index.toString());
92
+ }
93
+ return evaluatedExpression;
94
+ }
95
+ /**
96
+ * Builds the functions needed to operate with descriptors using an external elliptic curve (ecc) library.
97
+ * @param {Object} ecc - an object containing elliptic curve operations, such as [tiny-secp256k1](https://github.com/bitcoinjs/tiny-secp256k1) or [@bitcoinerlab/secp256k1](https://github.com/bitcoinerlab/secp256k1).
98
+ * @returns {Object} an object containing functions, `parse` and `checksum`.
99
+ * @namespace
100
+ */
101
+ function DescriptorsFactory(ecc) {
102
+ var _Descriptor_instances, _Descriptor_payment, _Descriptor_preimages, _Descriptor_signersPubKeys, _Descriptor_miniscript, _Descriptor_witnessScript, _Descriptor_redeemScript, _Descriptor_isSegwit, _Descriptor_expandedExpression, _Descriptor_expandedMiniscript, _Descriptor_expansionMap, _Descriptor_network, _Descriptor_getTimeConstraints, _Descriptor_assertPsbtInput;
103
+ const BIP32 = (0, bip32_1.BIP32Factory)(ecc);
104
+ const ECPair = (0, ecpair_1.ECPairFactory)(ecc);
105
+ const signatureValidator = (pubkey, msghash, signature) => ECPair.fromPublicKey(pubkey).verify(msghash, signature);
106
+ /*
107
+ * Takes a string key expression (xpub, xprv, pubkey or wif) and parses it
108
+ */
109
+ const parseKeyExpression = ({ keyExpression, isSegwit, network = bitcoinjs_lib_1.networks.bitcoin }) => {
110
+ return (0, keyExpressions_1.parseKeyExpression)({
111
+ keyExpression,
112
+ network,
113
+ ...(typeof isSegwit === 'boolean' ? { isSegwit } : {}),
114
+ ECPair,
115
+ BIP32
116
+ });
117
+ };
118
+ /**
119
+ * Expand a miniscript to a generalized form using variables instead of key
120
+ * expressions. Variables will be of this form: @0, @1, ...
121
+ * This is done so that it can be compiled with compileMiniscript and
122
+ * satisfied with satisfier.
123
+ * Also compute pubkeys from descriptors to use them later.
124
+ */
125
+ function expandMiniscript({ miniscript, isSegwit, network = bitcoinjs_lib_1.networks.bitcoin }) {
126
+ return (0, miniscript_1.expandMiniscript)({
127
+ miniscript,
128
+ isSegwit,
129
+ network,
130
+ BIP32,
131
+ ECPair
132
+ });
133
+ }
134
+ class Descriptor {
135
+ /**
136
+ * @param {Object} params
137
+ * @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
+ * @param {boolean} [params.checksumRequired=false] - A flag indicating whether the descriptor is required to include a checksum.
140
+ * @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).
141
+ *
142
+ * @see {@link https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/payments/index.d.ts}
143
+ * @throws {Error} - when descriptor is invalid
144
+ */
145
+ constructor({ expression, index, checksumRequired = false, allowMiniscriptInP2SH = false, network = bitcoinjs_lib_1.networks.bitcoin, preimages = [], signersPubKeys }) {
146
+ var _a, _b, _c, _d, _e, _f;
147
+ _Descriptor_instances.add(this);
148
+ _Descriptor_payment.set(this, void 0);
149
+ _Descriptor_preimages.set(this, []);
150
+ _Descriptor_signersPubKeys.set(this, void 0);
151
+ _Descriptor_miniscript.set(this, void 0);
152
+ _Descriptor_witnessScript.set(this, void 0);
153
+ _Descriptor_redeemScript.set(this, void 0);
154
+ //isSegwit true if witnesses are needed to the spend coins sent to this descriptor.
155
+ //may be unset because we may get addr(P2SH) which we don't know if they have segwit.
156
+ _Descriptor_isSegwit.set(this, void 0);
157
+ _Descriptor_expandedExpression.set(this, void 0);
158
+ _Descriptor_expandedMiniscript.set(this, void 0);
159
+ _Descriptor_expansionMap.set(this, void 0);
160
+ _Descriptor_network.set(this, void 0);
161
+ __classPrivateFieldSet(this, _Descriptor_network, network, "f");
162
+ __classPrivateFieldSet(this, _Descriptor_preimages, preimages, "f");
163
+ if (typeof expression !== 'string')
164
+ throw new Error(`Error: invalid descriptor type`);
165
+ //Verify and remove checksum (if exists) and
166
+ //particularize range descriptor for index (if desc is range descriptor)
167
+ const evaluatedExpression = evaluate({
168
+ expression,
169
+ ...(index !== undefined ? { index } : {}),
170
+ checksumRequired
171
+ });
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
+ }
402
+ if (signersPubKeys) {
403
+ __classPrivateFieldSet(this, _Descriptor_signersPubKeys, signersPubKeys, "f");
404
+ }
405
+ else {
406
+ if (__classPrivateFieldGet(this, _Descriptor_expansionMap, "f")) {
407
+ __classPrivateFieldSet(this, _Descriptor_signersPubKeys, Object.values(__classPrivateFieldGet(this, _Descriptor_expansionMap, "f")).map(keyInfo => keyInfo.pubkey), "f");
408
+ }
409
+ else {
410
+ //We should only miss expansionMap in addr() expressions:
411
+ if (!evaluatedExpression.match(RE.reAddrAnchored)) {
412
+ throw new Error(`Error: expansionMap not available for expression ${expression} that is not an address`);
413
+ }
414
+ __classPrivateFieldSet(this, _Descriptor_signersPubKeys, [this.getScriptPubKey()], "f");
415
+ }
416
+ }
417
+ }
418
+ getPayment() {
419
+ return __classPrivateFieldGet(this, _Descriptor_payment, "f");
420
+ }
421
+ getAddress() {
422
+ if (!__classPrivateFieldGet(this, _Descriptor_payment, "f").address)
423
+ throw new Error(`Error: could extract an address from the payment`);
424
+ return __classPrivateFieldGet(this, _Descriptor_payment, "f").address;
425
+ }
426
+ getScriptPubKey() {
427
+ if (!__classPrivateFieldGet(this, _Descriptor_payment, "f").output)
428
+ throw new Error(`Error: could extract output.script from the payment`);
429
+ return __classPrivateFieldGet(this, _Descriptor_payment, "f").output;
430
+ }
431
+ getScriptSatisfaction(signatures) {
432
+ const miniscript = __classPrivateFieldGet(this, _Descriptor_miniscript, "f");
433
+ const expandedMiniscript = __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f");
434
+ const expansionMap = __classPrivateFieldGet(this, _Descriptor_expansionMap, "f");
435
+ if (miniscript === undefined ||
436
+ expandedMiniscript === undefined ||
437
+ expansionMap === undefined)
438
+ throw new Error(`Error: cannot get satisfaction from not expanded miniscript ${miniscript}`);
439
+ //Note that we pass the nLockTime and nSequence that is deduced
440
+ //using preimages and signersPubKeys.
441
+ //satisfyMiniscript will make sure
442
+ //that the actual solution given, using real signatures, still meets the
443
+ //same nLockTime and nSequence constraints
444
+ const scriptSatisfaction = (0, miniscript_1.satisfyMiniscript)({
445
+ expandedMiniscript,
446
+ expansionMap,
447
+ signatures,
448
+ preimages: __classPrivateFieldGet(this, _Descriptor_preimages, "f"),
449
+ //Here we pass the TimeConstraints obtained using signersPubKeys to
450
+ //verify that the solutions found using the final signatures have not
451
+ //changed
452
+ timeConstraints: {
453
+ nLockTime: this.getLockTime(),
454
+ nSequence: this.getSequence()
455
+ }
456
+ }).scriptSatisfaction;
457
+ if (!scriptSatisfaction)
458
+ throw new Error(`Error: could not produce a valid satisfaction`);
459
+ return scriptSatisfaction;
460
+ }
461
+ getSequence() {
462
+ return __classPrivateFieldGet(this, _Descriptor_instances, "m", _Descriptor_getTimeConstraints).call(this)?.nSequence;
463
+ }
464
+ getLockTime() {
465
+ return __classPrivateFieldGet(this, _Descriptor_instances, "m", _Descriptor_getTimeConstraints).call(this)?.nLockTime;
466
+ }
467
+ getWitnessScript() {
468
+ return __classPrivateFieldGet(this, _Descriptor_witnessScript, "f");
469
+ }
470
+ getRedeemScript() {
471
+ return __classPrivateFieldGet(this, _Descriptor_redeemScript, "f");
472
+ }
473
+ getNetwork() {
474
+ return __classPrivateFieldGet(this, _Descriptor_network, "f");
475
+ }
476
+ isSegwit() {
477
+ return __classPrivateFieldGet(this, _Descriptor_isSegwit, "f");
478
+ }
479
+ /**
480
+ * Updates a Psbt where the descriptor describes an utxo.
481
+ * The txHex (nonWitnessUtxo) and vout of the utxo must be passed.
482
+ *
483
+ * updatePsbt adds an input to the psbt and updates the tx locktime if needed.
484
+ * It also adds a new input to the Psbt based on txHex
485
+ * It returns the number of the input that is added.
486
+ * psbt and vout are mandatory. Also pass txHex.
487
+ *
488
+ * The following is not recommended but, alternatively, ONLY for Segwit inputs,
489
+ * you can pass txId and value, instead of txHex.
490
+ * If you do so, it is your responsibility to make sure that `value` is
491
+ * correct to avoid possible fee vulnerability attacks:
492
+ * https://github.com/bitcoinjs/bitcoinjs-lib/issues/1625
493
+ * Note that HW wallets require the full txHex also for Segwit anyways:
494
+ * https://blog.trezor.io/details-of-firmware-updates-for-trezor-one-version-1-9-1-and-trezor-model-t-version-2-3-1-1eba8f60f2dd
495
+ *
496
+ * In doubt, simply pass txHex (and you can skip passing txId and value) and
497
+ * you shall be fine.
498
+ */
499
+ updatePsbt({ psbt, txHex, txId, value, vout //vector output index
500
+ }) {
501
+ if (txHex === undefined) {
502
+ console.warn(`Warning: missing txHex may allow fee attacks`);
503
+ }
504
+ const isSegwit = this.isSegwit();
505
+ if (isSegwit === undefined) {
506
+ //This should only happen when using addr() expressions
507
+ throw new Error(`Error: could not determine whether this is a segwit descriptor`);
508
+ }
509
+ return (0, psbt_1.updatePsbt)({
510
+ psbt,
511
+ vout,
512
+ ...(txHex !== undefined ? { txHex } : {}),
513
+ ...(txId !== undefined ? { txId } : {}),
514
+ ...(value !== undefined ? { value } : {}),
515
+ sequence: this.getSequence(),
516
+ locktime: this.getLockTime(),
517
+ keysInfo: __classPrivateFieldGet(this, _Descriptor_expansionMap, "f") ? Object.values(__classPrivateFieldGet(this, _Descriptor_expansionMap, "f")) : [],
518
+ scriptPubKey: this.getScriptPubKey(),
519
+ isSegwit,
520
+ witnessScript: this.getWitnessScript(),
521
+ redeemScript: this.getRedeemScript()
522
+ });
523
+ }
524
+ finalizePsbtInput({ index, psbt, validate = true }) {
525
+ if (validate &&
526
+ !psbt.validateSignaturesOfInput(index, signatureValidator)) {
527
+ throw new Error(`Error: invalid signatures on input ${index}`);
528
+ }
529
+ //An index must be passed since finding the index in the psbt cannot be
530
+ //done:
531
+ //Imagine the case where you received money twice to
532
+ //the same miniscript-based address. You would have the same scriptPubKey,
533
+ //same sequences, ... The descriptor does not store the hash of the previous
534
+ //transaction since it is a general Descriptor object. Indices must be kept
535
+ //out of the scope of this class and then passed.
536
+ const signatures = psbt.data.inputs[index]?.partialSig;
537
+ if (!signatures)
538
+ throw new Error(`Error: cannot finalize without signatures`);
539
+ __classPrivateFieldGet(this, _Descriptor_instances, "m", _Descriptor_assertPsbtInput).call(this, { index, psbt });
540
+ if (!__classPrivateFieldGet(this, _Descriptor_miniscript, "f")) {
541
+ //Use standard finalizers
542
+ psbt.finalizeInput(index);
543
+ }
544
+ else {
545
+ const scriptSatisfaction = this.getScriptSatisfaction(signatures);
546
+ psbt.finalizeInput(index, (0, psbt_1.finalScriptsFuncFactory)(scriptSatisfaction, __classPrivateFieldGet(this, _Descriptor_network, "f")));
547
+ }
548
+ }
549
+ expand() {
550
+ return {
551
+ ...(__classPrivateFieldGet(this, _Descriptor_expandedExpression, "f") !== undefined
552
+ ? { expandedExpression: __classPrivateFieldGet(this, _Descriptor_expandedExpression, "f") }
553
+ : {}),
554
+ ...(__classPrivateFieldGet(this, _Descriptor_miniscript, "f") !== undefined
555
+ ? { miniscript: __classPrivateFieldGet(this, _Descriptor_miniscript, "f") }
556
+ : {}),
557
+ ...(__classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f") !== undefined
558
+ ? { expandedMiniscript: __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f") }
559
+ : {}),
560
+ ...(__classPrivateFieldGet(this, _Descriptor_expansionMap, "f") !== undefined
561
+ ? { expansionMap: __classPrivateFieldGet(this, _Descriptor_expansionMap, "f") }
562
+ : {})
563
+ };
564
+ }
565
+ }
566
+ _Descriptor_payment = new WeakMap(), _Descriptor_preimages = new WeakMap(), _Descriptor_signersPubKeys = new WeakMap(), _Descriptor_miniscript = new WeakMap(), _Descriptor_witnessScript = new WeakMap(), _Descriptor_redeemScript = new WeakMap(), _Descriptor_isSegwit = new WeakMap(), _Descriptor_expandedExpression = new WeakMap(), _Descriptor_expandedMiniscript = new WeakMap(), _Descriptor_expansionMap = new WeakMap(), _Descriptor_network = new WeakMap(), _Descriptor_instances = new WeakSet(), _Descriptor_getTimeConstraints = function _Descriptor_getTimeConstraints() {
567
+ const miniscript = __classPrivateFieldGet(this, _Descriptor_miniscript, "f");
568
+ const preimages = __classPrivateFieldGet(this, _Descriptor_preimages, "f");
569
+ const expandedMiniscript = __classPrivateFieldGet(this, _Descriptor_expandedMiniscript, "f");
570
+ const expansionMap = __classPrivateFieldGet(this, _Descriptor_expansionMap, "f");
571
+ const signersPubKeys = __classPrivateFieldGet(this, _Descriptor_signersPubKeys, "f");
572
+ //Create a method. solvePreimages to solve them.
573
+ if (miniscript) {
574
+ if (expandedMiniscript === undefined || expansionMap === undefined)
575
+ throw new Error(`Error: cannot get time constraints from not expanded miniscript ${miniscript}`);
576
+ //We create some fakeSignatures since we may not have them yet.
577
+ //We only want to retrieve the nLockTime and nSequence of the satisfaction and
578
+ //signatures don't matter
579
+ const fakeSignatures = signersPubKeys.map(pubkey => ({
580
+ pubkey,
581
+ signature: Buffer.alloc(64, 0)
582
+ }));
583
+ const { nLockTime, nSequence } = (0, miniscript_1.satisfyMiniscript)({
584
+ expandedMiniscript,
585
+ expansionMap,
586
+ signatures: fakeSignatures,
587
+ preimages
588
+ });
589
+ return { nLockTime, nSequence };
590
+ }
591
+ else
592
+ return undefined;
593
+ }, _Descriptor_assertPsbtInput = function _Descriptor_assertPsbtInput({ psbt, index }) {
594
+ const input = psbt.data.inputs[index];
595
+ const txInput = psbt.txInputs[index];
596
+ if (!input || !txInput)
597
+ throw new Error(`Error: invalid input or txInput`);
598
+ const { sequence: inputSequence, index: vout } = txInput;
599
+ let scriptPubKey;
600
+ if (input.witnessUtxo)
601
+ scriptPubKey = input.witnessUtxo.script;
602
+ else {
603
+ if (!input.nonWitnessUtxo)
604
+ throw new Error(`Error: input should have either witnessUtxo or nonWitnessUtxo`);
605
+ const tx = bitcoinjs_lib_1.Transaction.fromBuffer(input.nonWitnessUtxo);
606
+ const out = tx.outs[vout];
607
+ if (!out)
608
+ throw new Error(`Error: utxo should exist`);
609
+ scriptPubKey = out.script;
610
+ }
611
+ const locktime = this.getLockTime() || 0;
612
+ let sequence = this.getSequence();
613
+ if (sequence === undefined && locktime !== 0)
614
+ sequence = 0xfffffffe;
615
+ if (sequence === undefined && locktime === 0)
616
+ sequence = 0xffffffff;
617
+ if (Buffer.compare(scriptPubKey, this.getScriptPubKey()) !== 0 ||
618
+ sequence !== inputSequence ||
619
+ locktime !== psbt.locktime ||
620
+ this.getWitnessScript() !== input.witnessScript ||
621
+ this.getRedeemScript() !== input.redeemScript) {
622
+ throw new Error(`Error: cannot finalize psbt index ${index} since it does not correspond to this descriptor`);
623
+ }
624
+ };
625
+ return { Descriptor, parseKeyExpression, ECPair, BIP32 };
626
+ }
627
+ exports.DescriptorsFactory = DescriptorsFactory;
@@ -0,0 +1,25 @@
1
+ import type { Psbt } from 'bitcoinjs-lib';
2
+ import type { DescriptorInterface } from './types';
3
+ export { DescriptorInterface, DescriptorInterfaceConstructor, ParseKeyExpression } from './types';
4
+ export { DescriptorsFactory } from './descriptors';
5
+ export { DescriptorChecksum as checksum } from './checksum';
6
+ import * as signers from './signers';
7
+ export { signers };
8
+ export declare function finalizePsbt({ psbt, descriptors, validate }: {
9
+ psbt: Psbt;
10
+ descriptors: DescriptorInterface[];
11
+ validate?: boolean | undefined;
12
+ }): void;
13
+ export { keyExpressionBIP32, keyExpressionLedger } from './keyExpressions';
14
+ import * as scriptExpressions from './scriptExpressions';
15
+ export { scriptExpressions };
16
+ import { AppClient } from '@bitcoinerlab/ledger';
17
+ import { LedgerState, getLedgerMasterFingerPrint, getLedgerXpub, registerLedgerWallet, assertLedgerApp } from './ledger';
18
+ export declare const ledger: {
19
+ getLedgerMasterFingerPrint: typeof getLedgerMasterFingerPrint;
20
+ getLedgerXpub: typeof getLedgerXpub;
21
+ registerLedgerWallet: typeof registerLedgerWallet;
22
+ assertLedgerApp: typeof assertLedgerApp;
23
+ AppClient: typeof AppClient;
24
+ };
25
+ export type { LedgerState };