@bitcoinerlab/descriptors-core 3.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.
Files changed (76) hide show
  1. package/README.md +710 -0
  2. package/dist/adapters/applyPR2137.d.ts +2 -0
  3. package/dist/adapters/applyPR2137.js +150 -0
  4. package/dist/adapters/bitcoinjs.d.ts +8 -0
  5. package/dist/adapters/bitcoinjs.js +36 -0
  6. package/dist/adapters/scure/address.d.ts +2 -0
  7. package/dist/adapters/scure/address.js +50 -0
  8. package/dist/adapters/scure/bip32.d.ts +2 -0
  9. package/dist/adapters/scure/bip32.js +16 -0
  10. package/dist/adapters/scure/common.d.ts +14 -0
  11. package/dist/adapters/scure/common.js +36 -0
  12. package/dist/adapters/scure/ecpair.d.ts +2 -0
  13. package/dist/adapters/scure/ecpair.js +58 -0
  14. package/dist/adapters/scure/payments.d.ts +2 -0
  15. package/dist/adapters/scure/payments.js +216 -0
  16. package/dist/adapters/scure/psbt.d.ts +43 -0
  17. package/dist/adapters/scure/psbt.js +382 -0
  18. package/dist/adapters/scure/script.d.ts +20 -0
  19. package/dist/adapters/scure/script.js +163 -0
  20. package/dist/adapters/scure/transaction.d.ts +2 -0
  21. package/dist/adapters/scure/transaction.js +32 -0
  22. package/dist/adapters/scure.d.ts +6 -0
  23. package/dist/adapters/scure.js +37 -0
  24. package/dist/adapters/scureKeys.d.ts +4 -0
  25. package/dist/adapters/scureKeys.js +135 -0
  26. package/dist/bip174.d.ts +87 -0
  27. package/dist/bip174.js +12 -0
  28. package/dist/bitcoinLib.d.ts +385 -0
  29. package/dist/bitcoinLib.js +19 -0
  30. package/dist/bitcoinjs-lib-internals.d.ts +6 -0
  31. package/dist/bitcoinjs-lib-internals.js +60 -0
  32. package/dist/bitcoinjs.d.ts +12 -0
  33. package/dist/bitcoinjs.js +18 -0
  34. package/dist/checksum.d.ts +6 -0
  35. package/dist/checksum.js +58 -0
  36. package/dist/crypto.d.ts +3 -0
  37. package/dist/crypto.js +79 -0
  38. package/dist/descriptors.d.ts +481 -0
  39. package/dist/descriptors.js +1888 -0
  40. package/dist/index.d.ts +23 -0
  41. package/dist/index.js +87 -0
  42. package/dist/keyExpressions.d.ts +124 -0
  43. package/dist/keyExpressions.js +310 -0
  44. package/dist/keyInterfaces.d.ts +5 -0
  45. package/dist/keyInterfaces.js +50 -0
  46. package/dist/ledger.d.ts +183 -0
  47. package/dist/ledger.js +618 -0
  48. package/dist/miniscript.d.ts +125 -0
  49. package/dist/miniscript.js +310 -0
  50. package/dist/multipath.d.ts +13 -0
  51. package/dist/multipath.js +76 -0
  52. package/dist/networkUtils.d.ts +3 -0
  53. package/dist/networkUtils.js +16 -0
  54. package/dist/networks.d.ts +16 -0
  55. package/dist/networks.js +31 -0
  56. package/dist/parseUtils.d.ts +7 -0
  57. package/dist/parseUtils.js +46 -0
  58. package/dist/psbt.d.ts +40 -0
  59. package/dist/psbt.js +228 -0
  60. package/dist/re.d.ts +31 -0
  61. package/dist/re.js +79 -0
  62. package/dist/resourceLimits.d.ts +28 -0
  63. package/dist/resourceLimits.js +84 -0
  64. package/dist/scriptExpressions.d.ts +95 -0
  65. package/dist/scriptExpressions.js +98 -0
  66. package/dist/scure.d.ts +4 -0
  67. package/dist/scure.js +10 -0
  68. package/dist/signers.d.ts +161 -0
  69. package/dist/signers.js +324 -0
  70. package/dist/tapMiniscript.d.ts +231 -0
  71. package/dist/tapMiniscript.js +524 -0
  72. package/dist/tapTree.d.ts +91 -0
  73. package/dist/tapTree.js +166 -0
  74. package/dist/types.d.ts +296 -0
  75. package/dist/types.js +4 -0
  76. package/package.json +148 -0
@@ -0,0 +1,1888 @@
1
+ "use strict";
2
+ // Copyright (c) 2026 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 () {
21
+ var ownKeys = function(o) {
22
+ ownKeys = Object.getOwnPropertyNames || function (o) {
23
+ var ar = [];
24
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
25
+ return ar;
26
+ };
27
+ return ownKeys(o);
28
+ };
29
+ return function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ })();
37
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
38
+ if (kind === "m") throw new TypeError("Private method is not writable");
39
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
40
+ 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");
41
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
42
+ };
43
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
44
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
45
+ 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");
46
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
47
+ };
48
+ var __importDefault = (this && this.__importDefault) || function (mod) {
49
+ return (mod && mod.__esModule) ? mod : { "default": mod };
50
+ };
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.DescriptorsFactory = DescriptorsFactory;
53
+ const lodash_memoize_1 = __importDefault(require("lodash.memoize")); //TODO: make sure this is propoely used
54
+ const bitcoinjs_lib_internals_1 = require("./bitcoinjs-lib-internals");
55
+ const varuint_bitcoin_1 = require("varuint-bitcoin");
56
+ const uint8array_tools_1 = require("uint8array-tools");
57
+ const psbt_1 = require("./psbt");
58
+ const checksum_1 = require("./checksum");
59
+ const networks_1 = require("./networks");
60
+ const keyExpressions_1 = require("./keyExpressions");
61
+ const RE = __importStar(require("./re"));
62
+ const miniscript_1 = require("./miniscript");
63
+ const tapTree_1 = require("./tapTree");
64
+ const tapMiniscript_1 = require("./tapMiniscript");
65
+ const parseUtils_1 = require("./parseUtils");
66
+ const multipath_1 = require("./multipath");
67
+ const resourceLimits_1 = require("./resourceLimits");
68
+ const ECDSA_FAKE_SIGNATURE_SIZE = 72;
69
+ const TAPROOT_FAKE_SIGNATURE_SIZE = 64;
70
+ /** Detect if the adapter was created with native bitcoinjs key factories. */
71
+ function isBitcoinJsLib(lib) {
72
+ const BITCOINJS_KEY_PROBE_PRIVKEY = Uint8Array.from([
73
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74
+ 0, 0, 0, 0, 0, 0, 1
75
+ ]);
76
+ const BITCOINJS_KEY_PROBE_SEED = new Uint8Array(32).fill(1);
77
+ try {
78
+ const maybeECPairWithFromPrivateKey = lib.ECPair;
79
+ const maybeBIP32WithFromSeed = lib.BIP32;
80
+ if (typeof maybeECPairWithFromPrivateKey.fromPrivateKey !== 'function')
81
+ return false;
82
+ if (typeof maybeBIP32WithFromSeed.fromSeed !== 'function')
83
+ return false;
84
+ const ecpair = maybeECPairWithFromPrivateKey.fromPrivateKey(BITCOINJS_KEY_PROBE_PRIVKEY);
85
+ const bip32 = maybeBIP32WithFromSeed.fromSeed(BITCOINJS_KEY_PROBE_SEED, networks_1.networks.regtest);
86
+ const looksLikeNativeECPair = typeof ecpair.toWIF === 'function' &&
87
+ typeof ecpair.compressed === 'boolean';
88
+ const looksLikeNativeBIP32 = bip32.chainCode instanceof Uint8Array &&
89
+ typeof bip32.toWIF === 'function' &&
90
+ typeof bip32.depth === 'number';
91
+ return looksLikeNativeECPair && looksLikeNativeBIP32;
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ }
97
+ function unsupportedKeyApi(apiName) {
98
+ const msg = `Error: ${apiName} is unavailable with this backend. ` +
99
+ `You initialized @bitcoinerlab/descriptors with a non-bitcoinjs lib. ` +
100
+ `Use DescriptorsFactory(ecc) or createBitcoinjsLib(ecc) for full bitcoinjs ${apiName} APIs.`;
101
+ return new Proxy({}, {
102
+ get(_target, prop) {
103
+ throw new Error(`${msg} Tried to access ${apiName}.${String(prop)}.`);
104
+ }
105
+ });
106
+ }
107
+ function vectorSize(someVector) {
108
+ const length = someVector.length;
109
+ return ((0, varuint_bitcoin_1.encodingLength)(length) +
110
+ someVector.reduce((sum, witness) => {
111
+ return sum + varSliceSize(witness);
112
+ }, 0));
113
+ }
114
+ function varSliceSize(someScript) {
115
+ const length = someScript.length;
116
+ return (0, varuint_bitcoin_1.encodingLength)(length) + length;
117
+ }
118
+ /*
119
+ * Returns a bare descriptor without checksum and particularized for a certain
120
+ * index (if desc was a range descriptor)
121
+ * @hidden
122
+ */
123
+ function evaluate({ descriptor, checksumRequired, index, change }) {
124
+ if (!descriptor)
125
+ throw new Error('You must provide a descriptor.');
126
+ const mChecksum = descriptor.match(String.raw `(${RE.reChecksum})$`);
127
+ if (mChecksum === null && checksumRequired === true)
128
+ throw new Error(`Error: descriptor ${descriptor} has not checksum`);
129
+ //evaluatedDescriptor: a bare desc without checksum and particularized for a certain
130
+ //index (if desc was a range descriptor)
131
+ let evaluatedDescriptor = descriptor;
132
+ if (mChecksum !== null) {
133
+ const checksum = mChecksum[0].substring(1); //remove the leading #
134
+ evaluatedDescriptor = descriptor.substring(0, descriptor.length - mChecksum[0].length);
135
+ if (checksum !== (0, checksum_1.DescriptorChecksum)(evaluatedDescriptor)) {
136
+ throw new Error(`Error: invalid descriptor checksum for ${descriptor}`);
137
+ }
138
+ }
139
+ evaluatedDescriptor = (0, multipath_1.resolveMultipathDescriptor)({
140
+ descriptor: evaluatedDescriptor,
141
+ ...(change !== undefined ? { change } : {})
142
+ });
143
+ if (index !== undefined) {
144
+ const mWildcard = evaluatedDescriptor.match(/\*/g);
145
+ if (mWildcard && mWildcard.length > 0) {
146
+ //From https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md
147
+ //To prevent a combinatorial explosion of the search space, if more than
148
+ //one of the multi() key arguments is a BIP32 wildcard path ending in /* or
149
+ //*', the multi() descriptor only matches multisig scripts with the ith
150
+ //child key from each wildcard path in lockstep, rather than scripts with
151
+ //any combination of child keys from each wildcard path.
152
+ //We extend this reasoning for musig for all cases
153
+ evaluatedDescriptor = evaluatedDescriptor.replaceAll('*', index.toString());
154
+ }
155
+ else
156
+ throw new Error(`Error: index passed for non-ranged descriptor: ${descriptor}`);
157
+ }
158
+ return evaluatedDescriptor;
159
+ }
160
+ // Helper: parse sortedmulti(M, k1, k2,...)
161
+ function parseSortedMulti(inner) {
162
+ // inner: "2,key1,key2,key3"
163
+ const parts = inner.split(',').map(p => p.trim());
164
+ if (parts.length < 2)
165
+ throw new Error(`sortedmulti(): must contain M and at least one key: ${inner}`);
166
+ const m = Number(parts[0]);
167
+ if (!Number.isInteger(m) || m < 1 || m > 20)
168
+ throw new Error(`sortedmulti(): invalid M=${parts[0]}`);
169
+ const keyExpressions = parts.slice(1);
170
+ if (keyExpressions.length < m)
171
+ throw new Error(`sortedmulti(): M cannot exceed number of keys: ${inner}`);
172
+ if (keyExpressions.length > 20)
173
+ throw new Error(`sortedmulti(): descriptors support up to 20 keys (per BIP 380/383).`);
174
+ return { m, keyExpressions };
175
+ }
176
+ const MAX_PUBKEYS_PER_MULTI_A = 999;
177
+ // Helper: parse sortedmulti_a(M, k1, k2,...)
178
+ function parseSortedMultiA(inner) {
179
+ const parts = inner.split(',').map(p => p.trim());
180
+ if (parts.length < 2)
181
+ throw new Error(`sortedmulti_a(): must contain M and at least one key: ${inner}`);
182
+ const m = Number(parts[0]);
183
+ if (!Number.isInteger(m) || m < 1)
184
+ throw new Error(`sortedmulti_a(): invalid M=${parts[0]}`);
185
+ const keyExpressions = parts.slice(1);
186
+ if (keyExpressions.length < m)
187
+ throw new Error(`sortedmulti_a(): M cannot exceed number of keys: ${inner}`);
188
+ if (keyExpressions.length > MAX_PUBKEYS_PER_MULTI_A)
189
+ throw new Error(`sortedmulti_a(): descriptors support up to ${MAX_PUBKEYS_PER_MULTI_A} keys.`);
190
+ return { m, keyExpressions };
191
+ }
192
+ function parseTrExpression(expression) {
193
+ if (!expression.startsWith('tr(') || !expression.endsWith(')'))
194
+ throw new Error(`Error: invalid descriptor ${expression}`);
195
+ const innerExpression = expression.slice(3, -1).trim();
196
+ if (!innerExpression)
197
+ throw new Error(`Error: invalid descriptor ${expression}`);
198
+ const splitResult = (0, parseUtils_1.splitTopLevelComma)({
199
+ expression: innerExpression,
200
+ onError: () => new Error(`Error: invalid descriptor ${expression}`)
201
+ });
202
+ //if no commas: innerExpression === keyExpression
203
+ if (!splitResult)
204
+ return { keyExpression: innerExpression };
205
+ return { keyExpression: splitResult.left, treeExpression: splitResult.right };
206
+ }
207
+ /**
208
+ * Constructs the necessary functions and classes for working with descriptors,
209
+ * using either an external elliptic curve (`ecc`) library or a core Bitcoin
210
+ * library (e.g.
211
+ * [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) or
212
+ * [@scure/btc-signer](https://github.com/paulmillr/scure-btc-signer)).
213
+ *
214
+ * Note:
215
+ * Most users do not need to call `DescriptorsFactory(...)` directly.
216
+ * - `@bitcoinerlab/descriptors` already provides the bitcoinjs-ready defaults.
217
+ * - `@bitcoinerlab/descriptors-scure` already provides the scure-ready defaults.
218
+ *
219
+ * This factory is mainly useful for:
220
+ * - backwards compatibility with pre-`3.1.x` bitcoinjs usage, and
221
+ * - advanced `@bitcoinerlab/descriptors-core` use cases where you want to bind
222
+ * a specific `TinySecp256k1Interface` or a custom `BitcoinLib`.
223
+ *
224
+ * In the default bitcoinjs package, the implicit `TinySecp256k1Interface` is
225
+ * `@bitcoinerlab/secp256k1`.
226
+ *
227
+ * Notably, it returns the {@link _Internal_.Output | `Output`} class, which
228
+ * provides methods to create, sign, and finalize transactions from descriptor
229
+ * expressions.
230
+ *
231
+ * The factory also returns utility methods like `expand` (detailed below)
232
+ * and `parseKeyExpression` (see {@link KeyExpressionParser}).
233
+ *
234
+ * Additionally, for convenience, the factory returns
235
+ * {@link https://github.com/bitcoinjs/bip32 | `BIP32`} and
236
+ * {@link https://github.com/bitcoinjs/ecpair | `ECPair`}.
237
+ * In bitcoinjs mode, these are the already initialized bitcoinjs factories,
238
+ * equivalent to `BIP32 = BIP32Factory(ecc)` and `ECPair = ECPairFactory(ecc)`.
239
+ * When using scure, prefer scure-native key types
240
+ * ({@link https://github.com/paulmillr/scure-bip32 | `HDKey`} and
241
+ * `Uint8Array` for private keys), which do not require key-factory initialization.
242
+ *
243
+ * @param {TinySecp256k1Interface | BitcoinLib} eccOrBitcoinLib - The core
244
+ * Bitcoin library input used by the factory.
245
+ *
246
+ * You can pass this parameter in three common ways:
247
+ *
248
+ * ```ts
249
+ * import { DescriptorsFactory } from '@bitcoinerlab/descriptors-core';
250
+ * import { createScureLib } from '@bitcoinerlab/descriptors-core/scure';
251
+ *
252
+ * const { Output } = DescriptorsFactory(createScureLib());
253
+ * ```
254
+ *
255
+ * ```ts
256
+ * import * as ecc from '@bitcoinerlab/secp256k1';
257
+ * import { DescriptorsFactory } from '@bitcoinerlab/descriptors-core';
258
+ * import { createBitcoinjsLib } from '@bitcoinerlab/descriptors-core/bitcoinjs';
259
+ *
260
+ * const { Output } = DescriptorsFactory(createBitcoinjsLib(ecc));
261
+ * ```
262
+ *
263
+ * ```ts
264
+ * import * as ecc from '@bitcoinerlab/secp256k1';
265
+ * import { DescriptorsFactory } from '@bitcoinerlab/descriptors';
266
+ *
267
+ * // Equivalent to `DescriptorsFactory(createBitcoinjsLib(ecc))`, but implicit.
268
+ * const { Output } = DescriptorsFactory(ecc);
269
+ * ```
270
+ */
271
+ function DescriptorsFactory(eccOrBitcoinLib) {
272
+ var _Output_instances, _Output_payment, _Output_preimages, _Output_signersPubKeys, _Output_miniscript, _Output_witnessScript, _Output_redeemScript, _Output_isSegwit, _Output_isTaproot, _Output_expandedExpression, _Output_expandedMiniscript, _Output_tapTreeExpression, _Output_tapTree, _Output_tapTreeInfo, _Output_taprootSpendPath, _Output_tapLeaf, _Output_expansionMap, _Output_network, _Output_resolveMiniscriptSignersPubKeys, _Output_assertMiniscriptSatisfactionResourceLimits, _Output_resolveTapTreeSignersPubKeys, _Output_getConstraints, _Output_assertPsbtInput;
273
+ // Detect whether we got a raw ecc interface or a full BitcoinLib adapter.
274
+ // BitcoinLib has a `payments` property; TinySecp256k1Interface does not.
275
+ let bitcoinLib;
276
+ if ('payments' in eccOrBitcoinLib && 'script' in eccOrBitcoinLib) {
277
+ bitcoinLib = eccOrBitcoinLib;
278
+ }
279
+ else {
280
+ let createBitcoinjsLib;
281
+ try {
282
+ // Lazy-load the bitcoinjs adapter to avoid hard-dep when using another backend
283
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
284
+ ({ createBitcoinjsLib } = require('./adapters/bitcoinjs'));
285
+ }
286
+ catch (error) {
287
+ throw new Error('Could not load the bitcoinjs backend. Install bitcoinjs-lib, bip32 and ecpair ' +
288
+ 'as peer dependencies, or use the scure backend with createScureLib(). ' +
289
+ 'Original error: ' +
290
+ (error instanceof Error ? error.message : String(error)));
291
+ }
292
+ bitcoinLib = createBitcoinjsLib(eccOrBitcoinLib);
293
+ }
294
+ const { payments, script: scriptLib } = bitcoinLib;
295
+ const { p2sh, p2wpkh, p2pkh, p2pk, p2wsh, p2tr } = payments;
296
+ const address = bitcoinLib.address;
297
+ const Transaction = bitcoinLib.Transaction;
298
+ const BIP32 = bitcoinLib.BIP32; //This is in fact BIP32APILike
299
+ const ECPair = bitcoinLib.ECPair; //This is in fact ECPairAPILike
300
+ const signatureValidator = (pubkey, msghash, signature) => {
301
+ if (pubkey.length === 32) {
302
+ //x-only
303
+ return bitcoinLib.verifySchnorr(msghash, pubkey, signature);
304
+ }
305
+ else {
306
+ return ECPair.fromPublicKey(pubkey).verify(msghash, signature);
307
+ }
308
+ };
309
+ /**
310
+ * Takes a string key expression (xpub, xprv, pubkey or wif) and parses it
311
+ */
312
+ const parseKeyExpression = ({ keyExpression, isSegwit, isTaproot, network = networks_1.networks.bitcoin }) => {
313
+ return (0, keyExpressions_1.parseKeyExpression)({
314
+ keyExpression,
315
+ network,
316
+ ...(typeof isSegwit === 'boolean' ? { isSegwit } : {}),
317
+ ...(typeof isTaproot === 'boolean' ? { isTaproot } : {}),
318
+ ECPair,
319
+ BIP32
320
+ });
321
+ };
322
+ /**
323
+ * Builds a taproot leaf expansion override for descriptor-level
324
+ * `sortedmulti_a(...)`.
325
+ *
326
+ * Why this exists:
327
+ * - `sortedmulti_a` is a descriptor script expression (not a Miniscript
328
+ * fragment).
329
+ *
330
+ * What this does:
331
+ * - Resolves each key expression to a concrete pubkey and builds a leaf-local
332
+ * placeholder map (`@0`, `@1`, ... in input order).
333
+ * - Derives the internal compilation form by sorting placeholders by pubkey
334
+ * bytes and lowering to `multi_a(...)`.
335
+ * - Compiles tapscript from that lowered form and returns it as override
336
+ * data.
337
+ *
338
+ * Returns `undefined` for non-`sortedmulti_a` leaves so normal taproot miniscript
339
+ * expansion/compilation is used.
340
+ */
341
+ function buildTapLeafSortedMultiAOverride({ expression, network = networks_1.networks.bitcoin }) {
342
+ if (!/\bsortedmulti_a\(/.test(expression))
343
+ return undefined;
344
+ const trimmed = expression.trim();
345
+ const match = trimmed.match(/^sortedmulti_a\((.*)\)$/);
346
+ if (!match)
347
+ throw new Error(`Error: sortedmulti_a() must be a standalone taproot leaf expression`);
348
+ const inner = match[1];
349
+ if (!inner)
350
+ throw new Error(`Error: invalid sortedmulti_a() expression: ${expression}`);
351
+ const { m, keyExpressions } = parseSortedMultiA(inner);
352
+ const keyInfos = keyExpressions.map(keyExpression => {
353
+ const keyInfo = parseKeyExpression({
354
+ keyExpression,
355
+ isSegwit: true,
356
+ isTaproot: true,
357
+ network
358
+ });
359
+ if (!keyInfo.pubkey)
360
+ throw new Error(`Error: sortedmulti_a() key must resolve to a concrete pubkey: ${keyExpression}`);
361
+ return keyInfo;
362
+ });
363
+ const expansionMap = {};
364
+ keyInfos.forEach((keyInfo, index) => {
365
+ expansionMap[`@${index}`] = keyInfo;
366
+ });
367
+ // sortedmulti_a is descriptor-level sugar. We preserve it in
368
+ // expandedExpression, but compile tapscript from its internal multi_a
369
+ // lowering with sorted placeholders.
370
+ const expandedExpression = `sortedmulti_a(${[
371
+ m,
372
+ ...Object.keys(expansionMap)
373
+ ].join(',')})`;
374
+ const compileExpandedMiniscript = (0, tapMiniscript_1.compileSortedMultiAExpandedExpression)({
375
+ expandedExpression,
376
+ expansionMap
377
+ });
378
+ const tapScript = (0, miniscript_1.miniscript2Script)({
379
+ expandedMiniscript: compileExpandedMiniscript,
380
+ expansionMap,
381
+ tapscript: true,
382
+ scriptLib
383
+ });
384
+ return { expandedExpression, expansionMap, tapScript };
385
+ }
386
+ function expand({ descriptor, index, change, checksumRequired = false, network = networks_1.networks.bitcoin, allowMiniscriptInP2SH = false }) {
387
+ if (!descriptor)
388
+ throw new Error(`descriptor not provided`);
389
+ let expandedExpression;
390
+ let miniscript;
391
+ let expansionMap;
392
+ let isSegwit;
393
+ let isTaproot;
394
+ let expandedMiniscript;
395
+ let tapTreeExpression;
396
+ let tapTree;
397
+ let tapTreeInfo;
398
+ let payment;
399
+ let witnessScript;
400
+ let redeemScript;
401
+ const isRanged = descriptor.indexOf('*') !== -1;
402
+ if (index !== undefined)
403
+ if (!Number.isInteger(index) || index < 0)
404
+ throw new Error(`Error: invalid index ${index}`);
405
+ //Verify and remove checksum (if exists) and
406
+ //particularize range descriptor for index (if desc is range descriptor)
407
+ const canonicalExpression = evaluate({
408
+ descriptor,
409
+ ...(index !== undefined ? { index } : {}),
410
+ ...(change !== undefined ? { change } : {}),
411
+ checksumRequired
412
+ });
413
+ const isCanonicalRanged = canonicalExpression.indexOf('*') !== -1;
414
+ //addr(ADDR)
415
+ if (canonicalExpression.match(RE.reAddrAnchored)) {
416
+ if (isRanged)
417
+ throw new Error(`Error: addr() cannot be ranged`);
418
+ const matchedAddress = canonicalExpression.match(RE.reAddrAnchored)?.[1]; //[1]-> whatever is found addr(->HERE<-)
419
+ if (!matchedAddress)
420
+ throw new Error(`Error: could not get an address in ${descriptor}`);
421
+ let output;
422
+ try {
423
+ output = address.toOutputScript(matchedAddress, network);
424
+ }
425
+ catch (e) {
426
+ void e;
427
+ throw new Error(`Error: invalid address ${matchedAddress}`);
428
+ }
429
+ try {
430
+ payment = p2pkh({ output, network });
431
+ isSegwit = false;
432
+ isTaproot = false;
433
+ }
434
+ catch (e) {
435
+ void e;
436
+ }
437
+ try {
438
+ payment = p2sh({ output, network });
439
+ // It assumes that an addr(SH_ADDRESS) is always a add(SH_WPKH) address
440
+ isSegwit = true;
441
+ isTaproot = false;
442
+ }
443
+ catch (e) {
444
+ void e;
445
+ }
446
+ try {
447
+ payment = p2wpkh({ output, network });
448
+ isSegwit = true;
449
+ isTaproot = false;
450
+ }
451
+ catch (e) {
452
+ void e;
453
+ }
454
+ try {
455
+ payment = p2wsh({ output, network });
456
+ isSegwit = true;
457
+ isTaproot = false;
458
+ }
459
+ catch (e) {
460
+ void e;
461
+ }
462
+ try {
463
+ payment = p2tr({ output, network });
464
+ isSegwit = true;
465
+ isTaproot = true;
466
+ }
467
+ catch (e) {
468
+ void e;
469
+ }
470
+ if (!payment) {
471
+ throw new Error(`Error: invalid address ${matchedAddress}`);
472
+ }
473
+ }
474
+ //pk(KEY)
475
+ else if (canonicalExpression.match(RE.rePkAnchored)) {
476
+ isSegwit = false;
477
+ isTaproot = false;
478
+ const keyExpression = canonicalExpression.match(RE.reNonSegwitKeyExp)?.[0];
479
+ if (!keyExpression)
480
+ throw new Error(`Error: keyExpression could not me extracted`);
481
+ if (canonicalExpression !== `pk(${keyExpression})`)
482
+ throw new Error(`Error: invalid expression ${descriptor}`);
483
+ expandedExpression = 'pk(@0)';
484
+ const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
485
+ expansionMap = { '@0': pKE };
486
+ if (!isCanonicalRanged) {
487
+ const pubkey = pKE.pubkey;
488
+ //Note there exists no address for p2pk, but we can still use the script
489
+ if (!pubkey)
490
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
491
+ payment = p2pk({ pubkey, network });
492
+ }
493
+ }
494
+ //pkh(KEY) - legacy
495
+ else if (canonicalExpression.match(RE.rePkhAnchored)) {
496
+ isSegwit = false;
497
+ isTaproot = false;
498
+ const keyExpression = canonicalExpression.match(RE.reNonSegwitKeyExp)?.[0];
499
+ if (!keyExpression)
500
+ throw new Error(`Error: keyExpression could not me extracted`);
501
+ if (canonicalExpression !== `pkh(${keyExpression})`)
502
+ throw new Error(`Error: invalid expression ${descriptor}`);
503
+ expandedExpression = 'pkh(@0)';
504
+ const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
505
+ expansionMap = { '@0': pKE };
506
+ if (!isCanonicalRanged) {
507
+ const pubkey = pKE.pubkey;
508
+ if (!pubkey)
509
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
510
+ payment = p2pkh({ pubkey, network });
511
+ }
512
+ }
513
+ //sh(wpkh(KEY)) - nested segwit
514
+ else if (canonicalExpression.match(RE.reShWpkhAnchored)) {
515
+ isSegwit = true;
516
+ isTaproot = false;
517
+ const keyExpression = canonicalExpression.match(RE.reSegwitKeyExp)?.[0];
518
+ if (!keyExpression)
519
+ throw new Error(`Error: keyExpression could not me extracted`);
520
+ if (canonicalExpression !== `sh(wpkh(${keyExpression}))`)
521
+ throw new Error(`Error: invalid expression ${descriptor}`);
522
+ expandedExpression = 'sh(wpkh(@0))';
523
+ const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
524
+ expansionMap = { '@0': pKE };
525
+ if (!isCanonicalRanged) {
526
+ const pubkey = pKE.pubkey;
527
+ if (!pubkey)
528
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
529
+ payment = p2sh({ redeem: p2wpkh({ pubkey, network }), network });
530
+ redeemScript = payment.redeem?.output;
531
+ if (!redeemScript)
532
+ throw new Error(`Error: could not calculate redeemScript for ${descriptor}`);
533
+ }
534
+ }
535
+ //wpkh(KEY) - native segwit
536
+ else if (canonicalExpression.match(RE.reWpkhAnchored)) {
537
+ isSegwit = true;
538
+ isTaproot = false;
539
+ const keyExpression = canonicalExpression.match(RE.reSegwitKeyExp)?.[0];
540
+ if (!keyExpression)
541
+ throw new Error(`Error: keyExpression could not me extracted`);
542
+ if (canonicalExpression !== `wpkh(${keyExpression})`)
543
+ throw new Error(`Error: invalid expression ${descriptor}`);
544
+ expandedExpression = 'wpkh(@0)';
545
+ const pKE = parseKeyExpression({ keyExpression, network, isSegwit });
546
+ expansionMap = { '@0': pKE };
547
+ if (!isCanonicalRanged) {
548
+ const pubkey = pKE.pubkey;
549
+ if (!pubkey)
550
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
551
+ payment = p2wpkh({ pubkey, network });
552
+ }
553
+ }
554
+ // sortedmulti script expressions
555
+ // sh(sortedmulti())
556
+ else if (canonicalExpression.match(RE.reShSortedMultiAnchored)) {
557
+ isSegwit = false;
558
+ isTaproot = false;
559
+ const inner = canonicalExpression.match(RE.reShSortedMultiAnchored)?.[1];
560
+ if (!inner)
561
+ throw new Error(`Error extracting sortedmulti() in ${descriptor}`);
562
+ const { m, keyExpressions } = parseSortedMulti(inner);
563
+ const pKEs = keyExpressions.map(k => parseKeyExpression({ keyExpression: k, network, isSegwit: false }));
564
+ const map = {};
565
+ pKEs.forEach((pke, i) => (map['@' + i] = pke));
566
+ expansionMap = map;
567
+ expandedExpression =
568
+ 'sh(sortedmulti(' +
569
+ [m, ...Object.keys(expansionMap).map(k => k)].join(',') +
570
+ '))';
571
+ if (!isCanonicalRanged) {
572
+ const pubkeys = pKEs.map(p => {
573
+ if (!p.pubkey)
574
+ throw new Error(`Error: key has no pubkey`);
575
+ return p.pubkey;
576
+ });
577
+ pubkeys.sort((a, b) => (0, uint8array_tools_1.compare)(a, b));
578
+ const redeem = payments.p2ms({ m, pubkeys, network });
579
+ redeemScript = redeem.output;
580
+ if (!redeemScript)
581
+ throw new Error(`Error creating redeemScript`);
582
+ payment = payments.p2sh({ redeem, network });
583
+ }
584
+ }
585
+ // wsh(sortedmulti())
586
+ else if (canonicalExpression.match(RE.reWshSortedMultiAnchored)) {
587
+ isSegwit = true;
588
+ isTaproot = false;
589
+ const inner = canonicalExpression.match(RE.reWshSortedMultiAnchored)?.[1];
590
+ if (!inner)
591
+ throw new Error(`Error extracting sortedmulti() in ${descriptor}`);
592
+ const { m, keyExpressions } = parseSortedMulti(inner);
593
+ const pKEs = keyExpressions.map(k => parseKeyExpression({ keyExpression: k, network, isSegwit: true }));
594
+ const map = {};
595
+ pKEs.forEach((pke, i) => (map['@' + i] = pke));
596
+ expansionMap = map;
597
+ expandedExpression =
598
+ 'wsh(sortedmulti(' +
599
+ [m, ...Object.keys(expansionMap).map(k => k)].join(',') +
600
+ '))';
601
+ if (!isCanonicalRanged) {
602
+ const pubkeys = pKEs.map(p => {
603
+ if (!p.pubkey)
604
+ throw new Error(`Error: key has no pubkey`);
605
+ return p.pubkey;
606
+ });
607
+ pubkeys.sort((a, b) => (0, uint8array_tools_1.compare)(a, b));
608
+ const redeem = payments.p2ms({ m, pubkeys, network });
609
+ witnessScript = redeem.output;
610
+ if (!witnessScript)
611
+ throw new Error(`Error computing witnessScript`);
612
+ payment = payments.p2wsh({ redeem, network });
613
+ }
614
+ }
615
+ // sh(wsh(sortedmulti()))
616
+ else if (canonicalExpression.match(RE.reShWshSortedMultiAnchored)) {
617
+ isSegwit = true;
618
+ isTaproot = false;
619
+ const inner = canonicalExpression.match(RE.reShWshSortedMultiAnchored)?.[1];
620
+ if (!inner)
621
+ throw new Error(`Error extracting sortedmulti() in ${descriptor}`);
622
+ const { m, keyExpressions } = parseSortedMulti(inner);
623
+ const pKEs = keyExpressions.map(k => parseKeyExpression({ keyExpression: k, network, isSegwit: true }));
624
+ const map = {};
625
+ pKEs.forEach((pke, i) => (map['@' + i] = pke));
626
+ expansionMap = map;
627
+ expandedExpression =
628
+ 'sh(wsh(sortedmulti(' +
629
+ [m, ...Object.keys(expansionMap).map(k => k)].join(',') +
630
+ ')))';
631
+ if (!isCanonicalRanged) {
632
+ const pubkeys = pKEs.map(p => {
633
+ if (!p.pubkey)
634
+ throw new Error(`Error: key has no pubkey`);
635
+ return p.pubkey;
636
+ });
637
+ pubkeys.sort((a, b) => (0, uint8array_tools_1.compare)(a, b));
638
+ const redeem = payments.p2ms({ m, pubkeys, network });
639
+ const wsh = payments.p2wsh({ redeem, network });
640
+ witnessScript = redeem.output;
641
+ redeemScript = wsh.output;
642
+ payment = payments.p2sh({ redeem: wsh, network });
643
+ }
644
+ }
645
+ //sh(wsh(miniscript))
646
+ else if (canonicalExpression.match(RE.reShWshMiniscriptAnchored)) {
647
+ isSegwit = true;
648
+ isTaproot = false;
649
+ miniscript = canonicalExpression.match(RE.reShWshMiniscriptAnchored)?.[1]; //[1]-> whatever is found sh(wsh(->HERE<-))
650
+ if (!miniscript)
651
+ throw new Error(`Error: could not get miniscript in ${descriptor}`);
652
+ ({ expandedMiniscript, expansionMap } = expandMiniscript({
653
+ miniscript,
654
+ isSegwit,
655
+ network
656
+ }));
657
+ expandedExpression = `sh(wsh(${expandedMiniscript}))`;
658
+ if (!isCanonicalRanged) {
659
+ const script = (0, miniscript_1.miniscript2Script)({
660
+ expandedMiniscript,
661
+ expansionMap,
662
+ scriptLib
663
+ });
664
+ witnessScript = script;
665
+ if (script.byteLength > resourceLimits_1.MAX_STANDARD_P2WSH_SCRIPT_SIZE) {
666
+ throw new Error(`Error: script is too large, ${script.byteLength} bytes is larger than ${resourceLimits_1.MAX_STANDARD_P2WSH_SCRIPT_SIZE} bytes`);
667
+ }
668
+ (0, resourceLimits_1.assertScriptNonPushOnlyOpsLimit)({ script, scriptLib });
669
+ payment = p2sh({
670
+ redeem: p2wsh({ redeem: { output: script, network }, network }),
671
+ network
672
+ });
673
+ redeemScript = payment.redeem?.output;
674
+ if (!redeemScript)
675
+ throw new Error(`Error: could not calculate redeemScript for ${descriptor}`);
676
+ }
677
+ }
678
+ //sh(miniscript)
679
+ else if (canonicalExpression.match(RE.reShMiniscriptAnchored)) {
680
+ //isSegwit false because we know it's a P2SH of a miniscript and not a
681
+ //P2SH that embeds a witness payment.
682
+ isSegwit = false;
683
+ isTaproot = false;
684
+ miniscript = canonicalExpression.match(RE.reShMiniscriptAnchored)?.[1]; //[1]-> whatever is found sh(->HERE<-)
685
+ if (!miniscript)
686
+ throw new Error(`Error: could not get miniscript in ${descriptor}`);
687
+ if (allowMiniscriptInP2SH === false &&
688
+ // These top-level script expressions are allowed inside sh(...).
689
+ // The sorted script expressions (`sortedmulti`, `sortedmulti_a`) are
690
+ // handled in dedicated descriptor/taproot branches and are intentionally
691
+ // not part of this miniscript gate.
692
+ // Here we only keep legacy top-level forms to avoid accepting arbitrary
693
+ // miniscript in P2SH unless explicitly enabled.
694
+ miniscript.search(/^(pk\(|pkh\(|wpkh\(|combo\(|multi\(|multi_a\()/) !==
695
+ 0) {
696
+ throw new Error(`Error: Miniscript expressions can only be used in wsh`);
697
+ }
698
+ ({ expandedMiniscript, expansionMap } = expandMiniscript({
699
+ miniscript,
700
+ isSegwit,
701
+ network
702
+ }));
703
+ expandedExpression = `sh(${expandedMiniscript})`;
704
+ if (!isCanonicalRanged) {
705
+ const script = (0, miniscript_1.miniscript2Script)({
706
+ expandedMiniscript,
707
+ expansionMap,
708
+ scriptLib
709
+ });
710
+ redeemScript = script;
711
+ if (script.byteLength > resourceLimits_1.MAX_SCRIPT_ELEMENT_SIZE) {
712
+ throw new Error(`Error: P2SH script is too large, ${script.byteLength} bytes is larger than ${resourceLimits_1.MAX_SCRIPT_ELEMENT_SIZE} bytes`);
713
+ }
714
+ (0, resourceLimits_1.assertScriptNonPushOnlyOpsLimit)({ script, scriptLib });
715
+ payment = p2sh({ redeem: { output: script, network }, network });
716
+ }
717
+ }
718
+ //wsh(miniscript)
719
+ else if (canonicalExpression.match(RE.reWshMiniscriptAnchored)) {
720
+ isSegwit = true;
721
+ isTaproot = false;
722
+ miniscript = canonicalExpression.match(RE.reWshMiniscriptAnchored)?.[1]; //[1]-> whatever is found wsh(->HERE<-)
723
+ if (!miniscript)
724
+ throw new Error(`Error: could not get miniscript in ${descriptor}`);
725
+ ({ expandedMiniscript, expansionMap } = expandMiniscript({
726
+ miniscript,
727
+ isSegwit,
728
+ network
729
+ }));
730
+ expandedExpression = `wsh(${expandedMiniscript})`;
731
+ if (!isCanonicalRanged) {
732
+ const script = (0, miniscript_1.miniscript2Script)({
733
+ expandedMiniscript,
734
+ expansionMap,
735
+ scriptLib
736
+ });
737
+ witnessScript = script;
738
+ if (script.byteLength > resourceLimits_1.MAX_STANDARD_P2WSH_SCRIPT_SIZE) {
739
+ throw new Error(`Error: script is too large, ${script.byteLength} bytes is larger than ${resourceLimits_1.MAX_STANDARD_P2WSH_SCRIPT_SIZE} bytes`);
740
+ }
741
+ (0, resourceLimits_1.assertScriptNonPushOnlyOpsLimit)({ script, scriptLib });
742
+ payment = p2wsh({ redeem: { output: script, network }, network });
743
+ }
744
+ }
745
+ //tr(KEY) or tr(KEY,TREE) - taproot
746
+ else if (canonicalExpression.startsWith('tr(')) {
747
+ isSegwit = true;
748
+ isTaproot = true;
749
+ const { keyExpression, treeExpression } = parseTrExpression(canonicalExpression);
750
+ expandedExpression = treeExpression
751
+ ? `tr(@0,${treeExpression})`
752
+ : 'tr(@0)';
753
+ const pKE = parseKeyExpression({
754
+ keyExpression,
755
+ network,
756
+ isSegwit,
757
+ isTaproot
758
+ });
759
+ expansionMap = { '@0': pKE };
760
+ if (treeExpression) {
761
+ tapTreeExpression = treeExpression;
762
+ tapTree = (0, tapTree_1.parseTapTreeExpression)(treeExpression);
763
+ if (!isCanonicalRanged) {
764
+ tapTreeInfo = (0, tapMiniscript_1.buildTapTreeInfo)({
765
+ tapTree,
766
+ network,
767
+ BIP32,
768
+ ECPair,
769
+ scriptLib,
770
+ // `leafExpansionOverride` runs per leaf expression.
771
+ // For non-matching leaves it returns undefined and
772
+ // normal miniscript expansion is used;
773
+ // for sortedmulti_a leaves it returns descriptor-level
774
+ // metadata plus precompiled tapscript bytes.
775
+ leafExpansionOverride: (expression) => buildTapLeafSortedMultiAOverride({ expression, network })
776
+ });
777
+ }
778
+ }
779
+ if (!isCanonicalRanged) {
780
+ const pubkey = pKE.pubkey;
781
+ if (!pubkey)
782
+ throw new Error(`Error: could not extract a pubkey from ${descriptor}`);
783
+ const internalPubkey = (0, tapMiniscript_1.normalizeTaprootPubkey)(pubkey);
784
+ if (treeExpression) {
785
+ if (!tapTreeInfo)
786
+ throw new Error(`Error: taproot tree info not available`);
787
+ payment = p2tr({
788
+ internalPubkey,
789
+ scriptTree: (0, tapMiniscript_1.tapTreeInfoToScriptTree)(tapTreeInfo),
790
+ network
791
+ });
792
+ }
793
+ else {
794
+ payment = p2tr({ internalPubkey, network });
795
+ }
796
+ }
797
+ }
798
+ else {
799
+ throw new Error(`Error: Could not parse descriptor ${descriptor}`);
800
+ }
801
+ return {
802
+ ...(payment !== undefined ? { payment } : {}),
803
+ ...(expandedExpression !== undefined ? { expandedExpression } : {}),
804
+ ...(miniscript !== undefined ? { miniscript } : {}),
805
+ ...(expansionMap !== undefined ? { expansionMap } : {}),
806
+ ...(isSegwit !== undefined ? { isSegwit } : {}),
807
+ ...(isTaproot !== undefined ? { isTaproot } : {}),
808
+ ...(expandedMiniscript !== undefined ? { expandedMiniscript } : {}),
809
+ ...(tapTreeExpression !== undefined ? { tapTreeExpression } : {}),
810
+ ...(tapTree !== undefined ? { tapTree } : {}),
811
+ ...(tapTreeInfo !== undefined ? { tapTreeInfo } : {}),
812
+ ...(redeemScript !== undefined ? { redeemScript } : {}),
813
+ ...(witnessScript !== undefined ? { witnessScript } : {}),
814
+ isRanged,
815
+ canonicalExpression
816
+ };
817
+ }
818
+ /**
819
+ * Expand a miniscript to a generalized form using variables instead of key
820
+ * expressions. Variables will be of this form: @0, @1, ...
821
+ * This is done so that it can be compiled with compileMiniscript and
822
+ * satisfied with satisfier.
823
+ * Also compute pubkeys from descriptors to use them later.
824
+ */
825
+ function expandMiniscript({ miniscript, isSegwit, network = networks_1.networks.bitcoin }) {
826
+ return (0, miniscript_1.expandMiniscript)({
827
+ miniscript,
828
+ isSegwit,
829
+ isTaproot: false, //TODO:
830
+ network,
831
+ BIP32,
832
+ ECPair
833
+ });
834
+ }
835
+ /**
836
+ * The `Output` class is the central component for managing descriptors.
837
+ * It facilitates the creation of outputs to receive funds and enables the
838
+ * signing and finalization of PSBTs (Partially Signed Bitcoin Transactions)
839
+ * for spending UTXOs (Unspent Transaction Outputs).
840
+ */
841
+ class Output {
842
+ /**
843
+ * @param options
844
+ * @throws {Error} - when descriptor is invalid
845
+ */
846
+ constructor({ descriptor, index, change, checksumRequired = false, allowMiniscriptInP2SH = false, network = networks_1.networks.bitcoin, preimages = [], signersPubKeys, taprootSpendPath, tapLeaf }) {
847
+ _Output_instances.add(this);
848
+ _Output_payment.set(this, void 0);
849
+ _Output_preimages.set(this, []);
850
+ _Output_signersPubKeys.set(this, void 0);
851
+ _Output_miniscript.set(this, void 0);
852
+ _Output_witnessScript.set(this, void 0);
853
+ _Output_redeemScript.set(this, void 0);
854
+ //isSegwit true if witnesses are needed to the spend coins sent to this descriptor.
855
+ //may be unset because we may get addr(P2SH) which we don't know if they have segwit.
856
+ _Output_isSegwit.set(this, void 0);
857
+ _Output_isTaproot.set(this, void 0);
858
+ _Output_expandedExpression.set(this, void 0);
859
+ _Output_expandedMiniscript.set(this, void 0);
860
+ _Output_tapTreeExpression.set(this, void 0);
861
+ _Output_tapTree.set(this, void 0);
862
+ _Output_tapTreeInfo.set(this, void 0);
863
+ _Output_taprootSpendPath.set(this, void 0);
864
+ _Output_tapLeaf.set(this, void 0);
865
+ _Output_expansionMap.set(this, void 0);
866
+ _Output_network.set(this, void 0);
867
+ __classPrivateFieldSet(this, _Output_network, network, "f");
868
+ __classPrivateFieldSet(this, _Output_preimages, preimages, "f");
869
+ if (typeof descriptor !== 'string')
870
+ throw new Error(`Error: invalid descriptor type`);
871
+ const expandedResult = expand({
872
+ descriptor,
873
+ ...(index !== undefined ? { index } : {}),
874
+ ...(change !== undefined ? { change } : {}),
875
+ checksumRequired,
876
+ network,
877
+ allowMiniscriptInP2SH
878
+ });
879
+ const isTaprootDescriptor = expandedResult.isTaproot === true;
880
+ const hasTapTree = expandedResult.expandedExpression?.startsWith('tr(@0,') ?? false;
881
+ const resolvedTaprootSpendPath = taprootSpendPath ?? (hasTapTree ? 'script' : 'key');
882
+ if (!isTaprootDescriptor) {
883
+ if (taprootSpendPath !== undefined || tapLeaf !== undefined)
884
+ throw new Error(`Error: taprootSpendPath/tapLeaf require a taproot descriptor`);
885
+ }
886
+ else {
887
+ if (taprootSpendPath === 'script' && !hasTapTree)
888
+ throw new Error(`Error: taprootSpendPath=script requires a tr(KEY,TREE) descriptor`);
889
+ if (resolvedTaprootSpendPath === 'key' && tapLeaf !== undefined)
890
+ throw new Error(`Error: tapLeaf cannot be used when taprootSpendPath is key`);
891
+ if (tapLeaf !== undefined && !hasTapTree)
892
+ throw new Error(`Error: tapLeaf can only be used with tr(KEY,TREE) descriptors`);
893
+ }
894
+ if (expandedResult.isRanged && index === undefined)
895
+ throw new Error(`Error: index was not provided for ranged descriptor`);
896
+ if (!expandedResult.payment)
897
+ throw new Error(`Error: could not extract a payment from ${descriptor}`);
898
+ __classPrivateFieldSet(this, _Output_payment, expandedResult.payment, "f");
899
+ if (expandedResult.expandedExpression !== undefined)
900
+ __classPrivateFieldSet(this, _Output_expandedExpression, expandedResult.expandedExpression, "f");
901
+ if (expandedResult.miniscript !== undefined)
902
+ __classPrivateFieldSet(this, _Output_miniscript, expandedResult.miniscript, "f");
903
+ if (expandedResult.expansionMap !== undefined)
904
+ __classPrivateFieldSet(this, _Output_expansionMap, expandedResult.expansionMap, "f");
905
+ if (expandedResult.isSegwit !== undefined)
906
+ __classPrivateFieldSet(this, _Output_isSegwit, expandedResult.isSegwit, "f");
907
+ if (expandedResult.isTaproot !== undefined)
908
+ __classPrivateFieldSet(this, _Output_isTaproot, expandedResult.isTaproot, "f");
909
+ if (expandedResult.expandedMiniscript !== undefined)
910
+ __classPrivateFieldSet(this, _Output_expandedMiniscript, expandedResult.expandedMiniscript, "f");
911
+ if (expandedResult.tapTreeExpression !== undefined)
912
+ __classPrivateFieldSet(this, _Output_tapTreeExpression, expandedResult.tapTreeExpression, "f");
913
+ if (expandedResult.tapTree !== undefined)
914
+ __classPrivateFieldSet(this, _Output_tapTree, expandedResult.tapTree, "f");
915
+ if (expandedResult.tapTreeInfo !== undefined)
916
+ __classPrivateFieldSet(this, _Output_tapTreeInfo, expandedResult.tapTreeInfo, "f");
917
+ if (expandedResult.redeemScript !== undefined)
918
+ __classPrivateFieldSet(this, _Output_redeemScript, expandedResult.redeemScript, "f");
919
+ if (expandedResult.witnessScript !== undefined)
920
+ __classPrivateFieldSet(this, _Output_witnessScript, expandedResult.witnessScript, "f");
921
+ if (signersPubKeys)
922
+ __classPrivateFieldSet(this, _Output_signersPubKeys, signersPubKeys, "f");
923
+ __classPrivateFieldSet(this, _Output_taprootSpendPath, resolvedTaprootSpendPath, "f");
924
+ if (tapLeaf !== undefined)
925
+ __classPrivateFieldSet(this, _Output_tapLeaf, tapLeaf, "f");
926
+ this.getSequence = (0, lodash_memoize_1.default)(this.getSequence);
927
+ this.getLockTime = (0, lodash_memoize_1.default)(this.getLockTime);
928
+ const getSignaturesKey = (signatures) => signatures === 'DANGEROUSLY_USE_FAKE_SIGNATURES'
929
+ ? signatures
930
+ : signatures
931
+ .map(s => `${(0, uint8array_tools_1.toHex)(s.pubkey)}-${(0, uint8array_tools_1.toHex)(s.signature)}`)
932
+ .join('|');
933
+ this.guessOutput = (0, lodash_memoize_1.default)(this.guessOutput);
934
+ this.inputWeight = (0, lodash_memoize_1.default)(this.inputWeight,
935
+ // resolver function:
936
+ (isSegwitTx, signatures, options) => {
937
+ const segwitKey = isSegwitTx ? 'segwit' : 'non-segwit';
938
+ const signaturesKey = getSignaturesKey(signatures);
939
+ const taprootSighashKey = options?.taprootSighash ?? 'SIGHASH_DEFAULT';
940
+ return `${segwitKey}-${signaturesKey}-taprootSighash:${taprootSighashKey}`;
941
+ });
942
+ this.outputWeight = (0, lodash_memoize_1.default)(this.outputWeight);
943
+ }
944
+ /**
945
+ * Returns the compiled Script Satisfaction for a miniscript-based Output.
946
+ * The satisfaction is the unlocking script, derived by the Satisfier
947
+ * algorithm (https://bitcoin.sipa.be/miniscript/).
948
+ *
949
+ * This method uses a two-pass flow:
950
+ * 1) Planning: constraints (nLockTime/nSequence) are computed using fake
951
+ * signatures. This is done since the final solution may not need all the
952
+ * signatures in signersPubKeys. And we may avoid the user do extra
953
+ * signing (tedious op with HWW).
954
+ * 2) Signing: the provided signatures are used to build the final
955
+ * satisfaction, while enforcing the planned constraints so the same
956
+ * solution is selected. Not all the signatures of signersPubKeys may
957
+ * be required.
958
+ *
959
+ * The return value includes the satisfaction script and the constraints.
960
+ */
961
+ getScriptSatisfaction(
962
+ /**
963
+ * An array with all the signatures needed to
964
+ * build the Satisfaction of this miniscript-based `Output`.
965
+ *
966
+ * `signatures` must be passed using this format (pairs of `pubKey/signature`):
967
+ * `interface PartialSig { pubkey: Uint8Array; signature: Uint8Array; }`
968
+ */
969
+ signatures) {
970
+ const miniscript = __classPrivateFieldGet(this, _Output_miniscript, "f");
971
+ const expandedMiniscript = __classPrivateFieldGet(this, _Output_expandedMiniscript, "f");
972
+ const expansionMap = __classPrivateFieldGet(this, _Output_expansionMap, "f");
973
+ if (miniscript === undefined ||
974
+ expandedMiniscript === undefined ||
975
+ expansionMap === undefined)
976
+ throw new Error(`Error: cannot get satisfaction from not expanded miniscript ${miniscript}`);
977
+ //This crates the plans using fake signatures
978
+ const constraints = __classPrivateFieldGet(this, _Output_instances, "m", _Output_getConstraints).call(this);
979
+ const satisfaction = (0, miniscript_1.satisfyMiniscript)({
980
+ expandedMiniscript,
981
+ expansionMap,
982
+ signatures,
983
+ preimages: __classPrivateFieldGet(this, _Output_preimages, "f"),
984
+ //Here we pass the TimeConstraints obtained using signersPubKeys to
985
+ //verify that the solutions found using the final signatures have not
986
+ //changed
987
+ timeConstraints: {
988
+ nLockTime: constraints?.nLockTime,
989
+ nSequence: constraints?.nSequence
990
+ },
991
+ scriptLib
992
+ });
993
+ __classPrivateFieldGet(this, _Output_instances, "m", _Output_assertMiniscriptSatisfactionResourceLimits).call(this, satisfaction.scriptSatisfaction);
994
+ return satisfaction;
995
+ }
996
+ /**
997
+ * Returns the taproot script‑path satisfaction for a tap miniscript
998
+ * descriptor. This mirrors {@link getScriptSatisfaction} and uses the same
999
+ * two‑pass plan/sign flow.
1000
+ *
1001
+ * In addition to nLockTime/nSequence, it returns the selected tapLeafHash
1002
+ * (the leaf chosen during planning) and the leaf’s tapscript.
1003
+ */
1004
+ getTapScriptSatisfaction(
1005
+ /**
1006
+ * An array with all the signatures needed to
1007
+ * build the Satisfaction of this miniscript-based `Output`.
1008
+ *
1009
+ * `signatures` must be passed using this format (pairs of `pubKey/signature`):
1010
+ * `interface PartialSig { pubkey: Uint8Array; signature: Uint8Array; }`
1011
+ */
1012
+ signatures) {
1013
+ if (__classPrivateFieldGet(this, _Output_taprootSpendPath, "f") !== 'script')
1014
+ throw new Error(`Error: taprootSpendPath is key; script-path satisfaction is not allowed`);
1015
+ const tapTreeInfo = __classPrivateFieldGet(this, _Output_tapTreeInfo, "f");
1016
+ if (!tapTreeInfo)
1017
+ throw new Error(`Error: taproot tree info not available`);
1018
+ const constraints = __classPrivateFieldGet(this, _Output_instances, "m", _Output_getConstraints).call(this);
1019
+ return (0, tapMiniscript_1.satisfyTapTree)({
1020
+ tapTreeInfo,
1021
+ preimages: __classPrivateFieldGet(this, _Output_preimages, "f"),
1022
+ signatures,
1023
+ ...(constraints?.tapLeafHash
1024
+ ? { tapLeaf: constraints.tapLeafHash }
1025
+ : {}),
1026
+ ...(constraints
1027
+ ? {
1028
+ timeConstraints: {
1029
+ nLockTime: constraints.nLockTime,
1030
+ nSequence: constraints.nSequence
1031
+ }
1032
+ }
1033
+ : {}),
1034
+ scriptLib
1035
+ });
1036
+ }
1037
+ /**
1038
+ * Creates and returns an instance of bitcoinjs-lib
1039
+ * [`Payment`](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/payments/index.ts)'s interface with the `scriptPubKey` of this `Output`.
1040
+ */
1041
+ getPayment() {
1042
+ return __classPrivateFieldGet(this, _Output_payment, "f");
1043
+ }
1044
+ /**
1045
+ * Returns the Bitcoin Address of this `Output`.
1046
+ */
1047
+ getAddress() {
1048
+ if (!__classPrivateFieldGet(this, _Output_payment, "f").address)
1049
+ throw new Error(`Error: could extract an address from the payment`);
1050
+ return __classPrivateFieldGet(this, _Output_payment, "f").address;
1051
+ }
1052
+ /**
1053
+ * Returns this `Output`'s scriptPubKey.
1054
+ */
1055
+ getScriptPubKey() {
1056
+ if (!__classPrivateFieldGet(this, _Output_payment, "f").output)
1057
+ throw new Error(`Error: could extract output.script from the payment`);
1058
+ return __classPrivateFieldGet(this, _Output_payment, "f").output;
1059
+ }
1060
+ /**
1061
+ * Gets the nSequence required to fulfill this `Output`.
1062
+ */
1063
+ getSequence() {
1064
+ return __classPrivateFieldGet(this, _Output_instances, "m", _Output_getConstraints).call(this)?.nSequence;
1065
+ }
1066
+ /**
1067
+ * Gets the nLockTime required to fulfill this `Output`.
1068
+ */
1069
+ getLockTime() {
1070
+ return __classPrivateFieldGet(this, _Output_instances, "m", _Output_getConstraints).call(this)?.nLockTime;
1071
+ }
1072
+ /**
1073
+ * Returns the tapleaf hash selected during planning for taproot script-path
1074
+ * spends. If signersPubKeys are provided, selection is optimized for those
1075
+ * pubkeys. If a specific tapLeaf selector is used in spending calls, this
1076
+ * reflects that selection.
1077
+ */
1078
+ getTapLeafHash() {
1079
+ return __classPrivateFieldGet(this, _Output_instances, "m", _Output_getConstraints).call(this)?.tapLeafHash;
1080
+ }
1081
+ /**
1082
+ * Gets the witnessScript required to fulfill this `Output`. Only applies to
1083
+ * Segwit outputs.
1084
+ */
1085
+ getWitnessScript() {
1086
+ return __classPrivateFieldGet(this, _Output_witnessScript, "f");
1087
+ }
1088
+ /**
1089
+ * Gets the redeemScript required to fullfill this `Output`. Only applies to
1090
+ * SH outputs: sh(wpkh), sh(wsh), sh(lockingScript).
1091
+ */
1092
+ getRedeemScript() {
1093
+ return __classPrivateFieldGet(this, _Output_redeemScript, "f");
1094
+ }
1095
+ /**
1096
+ * Gets the bitcoinjs-lib [`network`](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/networks.ts) used to create this `Output`.
1097
+ */
1098
+ getNetwork() {
1099
+ return __classPrivateFieldGet(this, _Output_network, "f");
1100
+ }
1101
+ /**
1102
+ * Whether this `Output` is Segwit.
1103
+ *
1104
+ * *NOTE:* When the descriptor in an input is `addr(address)`, it is assumed
1105
+ * that any `addr(SH_TYPE_ADDRESS)` is in fact a Segwit `SH_WPKH`
1106
+ * (Script Hash-Witness Public Key Hash).
1107
+ * For inputs using arbitrary scripts (not standard addresses),
1108
+ * use a descriptor in the format `sh(MINISCRIPT)`.
1109
+ *
1110
+ */
1111
+ isSegwit() {
1112
+ return __classPrivateFieldGet(this, _Output_isSegwit, "f");
1113
+ }
1114
+ /**
1115
+ * Whether this `Output` is Taproot.
1116
+ */
1117
+ isTaproot() {
1118
+ return __classPrivateFieldGet(this, _Output_isTaproot, "f");
1119
+ }
1120
+ /**
1121
+ * Attempts to determine the type of output script by testing it against
1122
+ * various payment types.
1123
+ *
1124
+ * This method tries to identify if the output is one of the following types:
1125
+ * - P2SH (Pay to Script Hash)
1126
+ * - P2WSH (Pay to Witness Script Hash)
1127
+ * - P2WPKH (Pay to Witness Public Key Hash)
1128
+ * - P2PKH (Pay to Public Key Hash)
1129
+ * - P2TR (Pay to Taproot)
1130
+ *
1131
+ * @returns An object { isPKH: boolean; isWPKH: boolean; isSH: boolean; isWSH: boolean; isTR: boolean;}
1132
+ * with boolean properties indicating the detected output type
1133
+ */
1134
+ guessOutput() {
1135
+ function guessSH(output) {
1136
+ try {
1137
+ payments.p2sh({ output });
1138
+ return true;
1139
+ }
1140
+ catch (err) {
1141
+ void err;
1142
+ return false;
1143
+ }
1144
+ }
1145
+ function guessWSH(output) {
1146
+ try {
1147
+ payments.p2wsh({ output });
1148
+ return true;
1149
+ }
1150
+ catch (err) {
1151
+ void err;
1152
+ return false;
1153
+ }
1154
+ }
1155
+ function guessWPKH(output) {
1156
+ try {
1157
+ payments.p2wpkh({ output });
1158
+ return true;
1159
+ }
1160
+ catch (err) {
1161
+ void err;
1162
+ return false;
1163
+ }
1164
+ }
1165
+ function guessPKH(output) {
1166
+ try {
1167
+ payments.p2pkh({ output });
1168
+ return true;
1169
+ }
1170
+ catch (err) {
1171
+ void err;
1172
+ return false;
1173
+ }
1174
+ }
1175
+ function guessTR(output) {
1176
+ try {
1177
+ payments.p2tr({ output });
1178
+ return true;
1179
+ }
1180
+ catch (err) {
1181
+ void err;
1182
+ return false;
1183
+ }
1184
+ }
1185
+ const isPKH = guessPKH(this.getScriptPubKey());
1186
+ const isWPKH = guessWPKH(this.getScriptPubKey());
1187
+ const isSH = guessSH(this.getScriptPubKey());
1188
+ const isWSH = guessWSH(this.getScriptPubKey());
1189
+ const isTR = guessTR(this.getScriptPubKey());
1190
+ if ([isPKH, isWPKH, isSH, isWSH, isTR].filter(Boolean).length > 1)
1191
+ throw new Error('Cannot have multiple output types.');
1192
+ return { isPKH, isWPKH, isSH, isWSH, isTR };
1193
+ }
1194
+ // References for inputWeight & outputWeight:
1195
+ // https://gist.github.com/junderw/b43af3253ea5865ed52cb51c200ac19c
1196
+ // https://bitcoinops.org/en/tools/calc-size/
1197
+ // Look for byteLength: https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/transaction.ts
1198
+ // https://github.com/bitcoinjs/coinselect/blob/master/utils.js
1199
+ // https://bitcoin.stackexchange.com/questions/111395/what-is-the-weight-of-a-p2tr-input
1200
+ /**
1201
+ * Computes the Weight Unit contributions of this Output as if it were the
1202
+ * input in a tx.
1203
+ *
1204
+ * *NOTE:* When the descriptor in an input is `addr(address)`, it is assumed
1205
+ * that any `addr(SH_TYPE_ADDRESS)` is in fact a Segwit `SH_WPKH`
1206
+ * (Script Hash-Witness Public Key Hash).
1207
+ *, Also any `addr(SINGLE_KEY_ADDRESS)` * is assumed to be a single key Taproot
1208
+ * address (like those defined in BIP86).
1209
+ * For inputs using arbitrary scripts (not standard addresses),
1210
+ * use a descriptor in the format `sh(MINISCRIPT)`, `wsh(MINISCRIPT)` or
1211
+ * `tr(KEY,TREE)` for taproot script-path expressions.
1212
+ */
1213
+ // NOTE(taproot-weight): Output instances are concrete. If descriptor has
1214
+ // wildcards, constructor requires `index`. No ranged-without-index
1215
+ // estimation is attempted here.
1216
+ // TODO(taproot-weight): Remaining items:
1217
+ // - Annex: not modeled; if annex is used, add witness item sizing.
1218
+ // - Taproot sighash defaults: options.taprootSighash currently drives fake
1219
+ // signature sizing; ensure coinselector passes the intended mode.
1220
+ // - After PSBT taproot script-path fields are fully populated, add regtest
1221
+ // integration fixtures comparing real tx vsize with inputWeight/outputWeight
1222
+ // estimates for taproot key-path and script-path spends.
1223
+ inputWeight(
1224
+ /**
1225
+ * Indicates if the transaction is a Segwit transaction.
1226
+ * If a transaction isSegwitTx, a single byte is then also required for
1227
+ * non-witness inputs to encode the length of the empty witness stack:
1228
+ * encodeLength(0) + 0 = 1
1229
+ * Read more:
1230
+ * https://gist.github.com/junderw/b43af3253ea5865ed52cb51c200ac19c?permalink_comment_id=4760512#gistcomment-4760512
1231
+ */
1232
+ isSegwitTx,
1233
+ /*
1234
+ * Array of `PartialSig`. Each `PartialSig` includes
1235
+ * a public key and its corresponding signature. This parameter
1236
+ * enables the accurate calculation of signature sizes for ECDSA.
1237
+ * Pass 'DANGEROUSLY_USE_FAKE_SIGNATURES' to assume
1238
+ * ECDSA_FAKE_SIGNATURE_SIZE bytes for ECDSA.
1239
+ * For taproot, the fake signature size is controlled by
1240
+ * options.taprootSighash (64 for 'SIGHASH_DEFAULT', 65
1241
+ * for 'non-SIGHASH_DEFAULT'). default value is SIGHASH_DEFAULT
1242
+ * Mainly used for testing.
1243
+ */
1244
+ signatures,
1245
+ /*
1246
+ * Options that affect taproot fake signature sizing.
1247
+ * taprootSighash: 'SIGHASH_DEFAULT' | 'non-SIGHASH_DEFAULT' (default: 'SIGHASH_DEFAULT').
1248
+ * This is only used when signatures === 'DANGEROUSLY_USE_FAKE_SIGNATURES'.
1249
+ */
1250
+ options = {
1251
+ taprootSighash: 'SIGHASH_DEFAULT'
1252
+ }) {
1253
+ const taprootSighash = options.taprootSighash ?? 'SIGHASH_DEFAULT';
1254
+ if (this.isSegwit() && !isSegwitTx)
1255
+ throw new Error(`a tx is segwit if at least one input is segwit`);
1256
+ //expand any miniscript-based descriptor. If not miniscript-based, then it's
1257
+ //an addr() descriptor. For those, we can only guess their type.
1258
+ const expansion = this.expand().expandedExpression;
1259
+ const { isPKH, isWPKH, isSH, isTR } = this.guessOutput();
1260
+ const errorMsg = `Input type not implemented. Currently supported: pkh(KEY), wpkh(KEY), tr(KEY), \
1261
+ sh(wpkh(KEY)), sh(wsh(MINISCRIPT)), sh(MINISCRIPT), wsh(MINISCRIPT), \
1262
+ addr(PKH_ADDRESS), addr(WPKH_ADDRESS), addr(SH_WPKH_ADDRESS), addr(SINGLE_KEY_ADDRESS). \
1263
+ expansion=${expansion}, isPKH=${isPKH}, isWPKH=${isWPKH}, isSH=${isSH}, isTR=${isTR}.`;
1264
+ if (!expansion && !isPKH && !isWPKH && !isSH && !isTR)
1265
+ throw new Error(errorMsg);
1266
+ const resolveEcdsaSignatureSize = () => {
1267
+ if (signatures === 'DANGEROUSLY_USE_FAKE_SIGNATURES')
1268
+ return ((0, varuint_bitcoin_1.encodingLength)(ECDSA_FAKE_SIGNATURE_SIZE) +
1269
+ ECDSA_FAKE_SIGNATURE_SIZE);
1270
+ if (signatures.length !== 1)
1271
+ throw new Error('More than one signture was not expected');
1272
+ const singleSignature = signatures[0];
1273
+ if (!singleSignature)
1274
+ throw new Error('Signatures not present');
1275
+ const length = singleSignature.signature.length;
1276
+ return (0, varuint_bitcoin_1.encodingLength)(length) + length;
1277
+ };
1278
+ const resolveMiniscriptSignatures = () => {
1279
+ const signerPubKeys = __classPrivateFieldGet(this, _Output_instances, "m", _Output_resolveMiniscriptSignersPubKeys).call(this);
1280
+ if (signatures === 'DANGEROUSLY_USE_FAKE_SIGNATURES') {
1281
+ return signerPubKeys.map(pubkey => ({
1282
+ pubkey,
1283
+ // https://transactionfee.info/charts/bitcoin-script-ecdsa-length/
1284
+ signature: new Uint8Array(ECDSA_FAKE_SIGNATURE_SIZE)
1285
+ }));
1286
+ }
1287
+ const providedSignerPubKeysSet = new Set(signatures.map(sig => (0, uint8array_tools_1.toHex)(sig.pubkey)));
1288
+ const missingSignerPubKeys = signerPubKeys.filter(pubkey => !providedSignerPubKeysSet.has((0, uint8array_tools_1.toHex)(pubkey)));
1289
+ if (missingSignerPubKeys.length > 0)
1290
+ throw new Error(`Error: inputWeight expected signatures for all planned miniscript signers. Missing ${missingSignerPubKeys.length} signer(s)`);
1291
+ const signerPubKeysSet = new Set(signerPubKeys.map(pubkey => (0, uint8array_tools_1.toHex)(pubkey)));
1292
+ return signatures.filter(sig => signerPubKeysSet.has((0, uint8array_tools_1.toHex)(sig.pubkey)));
1293
+ };
1294
+ const taprootFakeSignatureSize = taprootSighash === 'SIGHASH_DEFAULT'
1295
+ ? TAPROOT_FAKE_SIGNATURE_SIZE
1296
+ : TAPROOT_FAKE_SIGNATURE_SIZE + 1;
1297
+ const resolvePlannedTaprootRequiredPubKeys = () => {
1298
+ const tapTreeSignerPubKeys = __classPrivateFieldGet(this, _Output_instances, "m", _Output_resolveTapTreeSignersPubKeys).call(this).map(tapMiniscript_1.normalizeTaprootPubkey);
1299
+ const taggedFakeSignatures = tapTreeSignerPubKeys.map((pubkey, index) => ({
1300
+ pubkey,
1301
+ signature: new Uint8Array(taprootFakeSignatureSize).fill(index + 1)
1302
+ }));
1303
+ const plannedTaprootSatisfaction = this.getTapScriptSatisfaction(taggedFakeSignatures);
1304
+ const requiredPubkeys = taggedFakeSignatures
1305
+ .filter(fakeSignature => plannedTaprootSatisfaction.stackItems.some(stackItem => (0, uint8array_tools_1.compare)(stackItem, fakeSignature.signature) === 0))
1306
+ .map(fakeSignature => fakeSignature.pubkey);
1307
+ return Array.from(new Set(requiredPubkeys.map(pubkey => (0, uint8array_tools_1.toHex)(pubkey))))
1308
+ .map(hex => (0, uint8array_tools_1.fromHex)(hex))
1309
+ .map(tapMiniscript_1.normalizeTaprootPubkey);
1310
+ };
1311
+ const resolveTaprootSignatures = () => {
1312
+ if (signatures === 'DANGEROUSLY_USE_FAKE_SIGNATURES') {
1313
+ return __classPrivateFieldGet(this, _Output_instances, "m", _Output_resolveTapTreeSignersPubKeys).call(this).map(pubkey => ({
1314
+ pubkey,
1315
+ signature: new Uint8Array(taprootFakeSignatureSize)
1316
+ }));
1317
+ }
1318
+ const normalizedSignatures = signatures.map(sig => ({
1319
+ pubkey: (0, tapMiniscript_1.normalizeTaprootPubkey)(sig.pubkey),
1320
+ signature: sig.signature
1321
+ }));
1322
+ const plannedRequiredPubKeys = resolvePlannedTaprootRequiredPubKeys();
1323
+ const providedTapTreeSignerPubKeysSet = new Set(normalizedSignatures.map(sig => (0, uint8array_tools_1.toHex)(sig.pubkey)));
1324
+ const missingTapTreeSignerPubKeys = plannedRequiredPubKeys.filter(pubkey => !providedTapTreeSignerPubKeysSet.has((0, uint8array_tools_1.toHex)(pubkey)));
1325
+ if (missingTapTreeSignerPubKeys.length > 0)
1326
+ throw new Error(`Error: inputWeight expected signatures for the planned taproot script-path satisfaction. Missing ${missingTapTreeSignerPubKeys.length} signer(s)`);
1327
+ const plannedRequiredPubKeysSet = new Set(plannedRequiredPubKeys.map(pubkey => (0, uint8array_tools_1.toHex)(pubkey)));
1328
+ return normalizedSignatures.filter(sig => plannedRequiredPubKeysSet.has((0, uint8array_tools_1.toHex)(sig.pubkey)));
1329
+ };
1330
+ const resolveTaprootSignatureSize = () => {
1331
+ let length;
1332
+ if (signatures === 'DANGEROUSLY_USE_FAKE_SIGNATURES') {
1333
+ length = taprootFakeSignatureSize;
1334
+ }
1335
+ else {
1336
+ const normalizedSignatures = signatures.map(sig => ({
1337
+ pubkey: (0, tapMiniscript_1.normalizeTaprootPubkey)(sig.pubkey),
1338
+ signature: sig.signature
1339
+ }));
1340
+ const internalPubkey = this.getPayment().internalPubkey;
1341
+ if (!internalPubkey) {
1342
+ //addr() of tr addresses may not have internalPubkey
1343
+ if (normalizedSignatures.length !== 1)
1344
+ throw new Error('Error: inputWeight for addr(TR_ADDRESS) requires exactly one signature. Internal taproot pubkey is unavailable in addr() descriptors; use tr(KEY) for strict key matching.');
1345
+ const singleSignature = normalizedSignatures[0];
1346
+ if (!singleSignature)
1347
+ throw new Error('Signatures not present');
1348
+ length = singleSignature.signature.length;
1349
+ return (0, varuint_bitcoin_1.encodingLength)(length) + length;
1350
+ }
1351
+ const normalizedInternalPubkey = (0, tapMiniscript_1.normalizeTaprootPubkey)(internalPubkey);
1352
+ const keyPathSignatures = normalizedSignatures.filter(sig => (0, uint8array_tools_1.compare)(sig.pubkey, normalizedInternalPubkey) === 0);
1353
+ if (keyPathSignatures.length !== 1)
1354
+ throw new Error('More than one signture was not expected');
1355
+ const singleSignature = keyPathSignatures[0];
1356
+ if (!singleSignature)
1357
+ throw new Error('Signatures not present');
1358
+ length = singleSignature.signature.length;
1359
+ }
1360
+ return (0, varuint_bitcoin_1.encodingLength)(length) + length;
1361
+ };
1362
+ const taprootSpendPath = __classPrivateFieldGet(this, _Output_taprootSpendPath, "f");
1363
+ if (expansion ? expansion.startsWith('pkh(') : isPKH) {
1364
+ return (
1365
+ // Non-segwit: (txid:32) + (vout:4) + (sequence:4) + (script_len:1) + (sig:73) + (pubkey:34)
1366
+ (32 + 4 + 4 + 1 + resolveEcdsaSignatureSize() + 34) * 4 +
1367
+ //Segwit:
1368
+ (isSegwitTx ? 1 : 0));
1369
+ }
1370
+ else if (expansion ? expansion.startsWith('wpkh(') : isWPKH) {
1371
+ if (!isSegwitTx)
1372
+ throw new Error('Should be SegwitTx');
1373
+ return (
1374
+ // Non-segwit: (txid:32) + (vout:4) + (sequence:4) + (script_len:1)
1375
+ 41 * 4 +
1376
+ // Segwit: (push_count:1) + (sig:73) + (pubkey:34)
1377
+ (1 + resolveEcdsaSignatureSize() + 34));
1378
+ }
1379
+ else if (expansion ? expansion.startsWith('sh(wpkh(') : isSH) {
1380
+ if (!isSegwitTx)
1381
+ throw new Error('Should be SegwitTx');
1382
+ return (
1383
+ // Non-segwit: (txid:32) + (vout:4) + (sequence:4) + (script_len:1) + (p2wpkh:23)
1384
+ // -> p2wpkh_script: OP_0 OP_PUSH20 <public_key_hash>
1385
+ // -> p2wpkh: (script_len:1) + (script:22)
1386
+ 64 * 4 +
1387
+ // Segwit: (push_count:1) + (sig:73) + (pubkey:34)
1388
+ (1 + resolveEcdsaSignatureSize() + 34));
1389
+ }
1390
+ else if (expansion?.startsWith('sh(wsh(')) {
1391
+ if (!isSegwitTx)
1392
+ throw new Error('Should be SegwitTx');
1393
+ const witnessScript = this.getWitnessScript();
1394
+ if (!witnessScript)
1395
+ throw new Error('sh(wsh) must provide witnessScript');
1396
+ const payment = payments.p2sh({
1397
+ redeem: payments.p2wsh({
1398
+ redeem: {
1399
+ input: this.getScriptSatisfaction(resolveMiniscriptSignatures())
1400
+ .scriptSatisfaction,
1401
+ output: witnessScript
1402
+ }
1403
+ })
1404
+ });
1405
+ if (!payment || !payment.input || !payment.witness)
1406
+ throw new Error('Could not create payment');
1407
+ return (
1408
+ //Non-segwit
1409
+ 4 * (40 + varSliceSize(payment.input)) +
1410
+ //Segwit
1411
+ vectorSize(payment.witness));
1412
+ }
1413
+ else if (expansion?.startsWith('sh(')) {
1414
+ const redeemScript = this.getRedeemScript();
1415
+ if (!redeemScript)
1416
+ throw new Error('sh() must provide redeemScript');
1417
+ const payment = payments.p2sh({
1418
+ redeem: {
1419
+ input: this.getScriptSatisfaction(resolveMiniscriptSignatures())
1420
+ .scriptSatisfaction,
1421
+ output: redeemScript
1422
+ }
1423
+ });
1424
+ if (!payment || !payment.input)
1425
+ throw new Error('Could not create payment');
1426
+ if (payment.witness?.length)
1427
+ throw new Error('A legacy p2sh payment should not cointain a witness');
1428
+ return (
1429
+ //Non-segwit
1430
+ 4 * (40 + varSliceSize(payment.input)) +
1431
+ //Segwit:
1432
+ (isSegwitTx ? 1 : 0));
1433
+ }
1434
+ else if (expansion?.startsWith('wsh(')) {
1435
+ const witnessScript = this.getWitnessScript();
1436
+ if (!witnessScript)
1437
+ throw new Error('wsh must provide witnessScript');
1438
+ const payment = payments.p2wsh({
1439
+ redeem: {
1440
+ input: this.getScriptSatisfaction(resolveMiniscriptSignatures())
1441
+ .scriptSatisfaction,
1442
+ output: witnessScript
1443
+ }
1444
+ });
1445
+ if (!payment || !payment.input || !payment.witness)
1446
+ throw new Error('Could not create payment');
1447
+ return (
1448
+ //Non-segwit
1449
+ 4 * (40 + varSliceSize(payment.input)) +
1450
+ //Segwit
1451
+ vectorSize(payment.witness));
1452
+ // when tr(KEY,TREE): choose key-path or script-path based on
1453
+ // constructor taprootSpendPath policy.
1454
+ }
1455
+ else if (expansion?.startsWith('tr(@0,')) {
1456
+ if (!isSegwitTx)
1457
+ throw new Error('Should be SegwitTx');
1458
+ if (taprootSpendPath === 'key')
1459
+ return 41 * 4 + (0, varuint_bitcoin_1.encodingLength)(1) + resolveTaprootSignatureSize();
1460
+ const taprootSatisfaction = this.getTapScriptSatisfaction(resolveTaprootSignatures());
1461
+ return 41 * 4 + taprootSatisfaction.totalWitnessSize;
1462
+ }
1463
+ else if (isTR && (!expansion || expansion === 'tr(@0)')) {
1464
+ if (!isSegwitTx)
1465
+ throw new Error('Should be SegwitTx');
1466
+ return (
1467
+ // Non-segwit: (txid:32) + (vout:4) + (sequence:4) + (script_len:1)
1468
+ 41 * 4 +
1469
+ // Segwit: (push_count:1) + (sig_length(1) + schnorr_sig(64/65))
1470
+ ((0, varuint_bitcoin_1.encodingLength)(1) + resolveTaprootSignatureSize()));
1471
+ }
1472
+ else {
1473
+ throw new Error(errorMsg);
1474
+ }
1475
+ }
1476
+ /**
1477
+ * Computes the Weight Unit contributions of this Output as if it were the
1478
+ * output in a tx.
1479
+ */
1480
+ outputWeight() {
1481
+ //expand any miniscript-based descriptor. If not miniscript-based, then it's
1482
+ //an addr() descriptor. For those, we can only guess their type.
1483
+ const { isPKH, isWPKH, isSH, isWSH, isTR } = this.guessOutput();
1484
+ const errorMsg = `Output type not implemented. Currently supported: pkh=${isPKH}, wpkh=${isWPKH}, tr=${isTR}, sh=${isSH} and wsh=${isWSH}.`;
1485
+ if (isPKH) {
1486
+ // (p2pkh:26) + (amount:8)
1487
+ return 34 * 4;
1488
+ }
1489
+ else if (isWPKH) {
1490
+ // (p2wpkh:23) + (amount:8)
1491
+ return 31 * 4;
1492
+ }
1493
+ else if (isSH) {
1494
+ // (p2sh:24) + (amount:8)
1495
+ return 32 * 4;
1496
+ }
1497
+ else if (isWSH) {
1498
+ // (p2wsh:35) + (amount:8)
1499
+ return 43 * 4;
1500
+ }
1501
+ else if (isTR) {
1502
+ // (script_pubKey_length:1) + (p2t2(OP_1 OP_PUSH32 <schnorr_public_key>):34) + (amount:8)
1503
+ return 43 * 4;
1504
+ }
1505
+ else {
1506
+ throw new Error(errorMsg);
1507
+ }
1508
+ }
1509
+ /**
1510
+ * Sets this output as an input of the provided `psbt` and updates the
1511
+ * `psbt` locktime if required by the descriptor.
1512
+ *
1513
+ * `psbt` and `vout` are mandatory. Include `txHex` as well. The pair
1514
+ * `vout` and `txHex` define the transaction and output number this instance
1515
+ * pertains to.
1516
+ *
1517
+ * Though not advised, for Segwit inputs you can pass `txId` and `value`
1518
+ * in lieu of `txHex`. If doing so, ensure `value` accuracy to avoid
1519
+ * potential fee attacks -
1520
+ * [See this issue](https://github.com/bitcoinjs/bitcoinjs-lib/issues/1625).
1521
+ *
1522
+ * 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).
1523
+ *
1524
+ * When unsure, always use `txHex`, and skip `txId` and `value` for safety.
1525
+ *
1526
+ * Use `rbf` to mark whether this tx can be replaced with another with
1527
+ * higher fee while being in the mempool. Note that a tx will automatically
1528
+ * be marked as replacable if a single input requests it.
1529
+ * Note that any transaction using a relative timelock (nSequence < 0x80000000)
1530
+ * also falls within the RBF range (nSequence < 0xFFFFFFFE), making it
1531
+ * inherently replaceable. So don't set `rbf` to false if this is tx uses
1532
+ * relative time locks.
1533
+ *
1534
+ * @returns A finalizer function to be used after signing the `psbt`.
1535
+ * This function ensures that this input is properly finalized.
1536
+ * The finalizer completes the PSBT input by adding the unlocking script
1537
+ * (`scriptWitness` or `scriptSig`) that satisfies this `Output`'s spending
1538
+ * conditions. Because these scripts include signatures, you should finish
1539
+ * all signing operations before calling the finalizer.
1540
+ * The finalizer has this signature:
1541
+ *
1542
+ * `( { psbt, validate = true } : { psbt: PsbtLike | ScureTransactionLike; validate: boolean | undefined } ) => void`
1543
+ *
1544
+ * where `psbt` can be either a
1545
+ * {@link https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/psbt.ts | bitcoinjs-lib `Psbt`}
1546
+ * or a {@link https://github.com/paulmillr/scure-btc-signer | `@scure/btc-signer` `Transaction`}.
1547
+ *
1548
+ */
1549
+ updatePsbtAsInput({ psbt, txHex, txId, value, vout, //vector output index
1550
+ rbf = true }) {
1551
+ // Normalize to Psbt interface
1552
+ psbt = (0, psbt_1.toPsbt)(psbt);
1553
+ if (value !== undefined && typeof value !== 'bigint')
1554
+ throw new Error(`Error: value must be a bigint`);
1555
+ if (value !== undefined && value < 0n)
1556
+ throw new Error(`Error: value must be >= 0n`);
1557
+ if (txHex === undefined) {
1558
+ console.warn(`Warning: missing txHex may allow fee attacks`);
1559
+ }
1560
+ const isSegwit = this.isSegwit();
1561
+ if (isSegwit === undefined) {
1562
+ //This should only happen when using addr() expressions
1563
+ throw new Error(`Error: could not determine whether this is a segwit descriptor`);
1564
+ }
1565
+ const isTaproot = this.isTaproot();
1566
+ if (isTaproot === undefined) {
1567
+ //This should only happen when using addr() expressions
1568
+ throw new Error(`Error: could not determine whether this is a taproot descriptor`);
1569
+ }
1570
+ const paymentInternalPubkey = this.getPayment().internalPubkey;
1571
+ const tapInternalKey = isTaproot
1572
+ ? paymentInternalPubkey
1573
+ ? paymentInternalPubkey
1574
+ : undefined
1575
+ : undefined;
1576
+ let tapLeafScript;
1577
+ let tapBip32Derivation;
1578
+ if (isTaproot && __classPrivateFieldGet(this, _Output_taprootSpendPath, "f") === 'script') {
1579
+ const tapTreeInfo = __classPrivateFieldGet(this, _Output_tapTreeInfo, "f");
1580
+ if (!tapTreeInfo)
1581
+ throw new Error(`Error: taprootSpendPath=script requires taproot tree info`);
1582
+ if (!tapInternalKey)
1583
+ throw new Error(`Error: taprootSpendPath=script requires taproot internal key`);
1584
+ const taprootLeafMetadata = (0, tapMiniscript_1.buildTaprootLeafPsbtMetadata)({
1585
+ tapTreeInfo,
1586
+ internalPubkey: tapInternalKey,
1587
+ payments
1588
+ });
1589
+ tapLeafScript = taprootLeafMetadata.map(({ leaf, controlBlock }) => ({
1590
+ script: leaf.tapScript,
1591
+ leafVersion: leaf.version,
1592
+ controlBlock
1593
+ }));
1594
+ const internalKeyInfo = __classPrivateFieldGet(this, _Output_expansionMap, "f")?.['@0'];
1595
+ if (!internalKeyInfo)
1596
+ throw new Error(`Error: taproot internal key info not available in expansionMap`);
1597
+ tapBip32Derivation = (0, tapMiniscript_1.buildTaprootBip32Derivations)({
1598
+ tapTreeInfo,
1599
+ internalKeyInfo
1600
+ });
1601
+ }
1602
+ const index = (0, psbt_1.addPsbtInput)({
1603
+ psbt,
1604
+ vout,
1605
+ ...(txHex !== undefined ? { txHex } : {}),
1606
+ ...(txId !== undefined ? { txId } : {}),
1607
+ ...(value !== undefined ? { value } : {}),
1608
+ tapInternalKey,
1609
+ tapLeafScript,
1610
+ tapBip32Derivation,
1611
+ sequence: this.getSequence(),
1612
+ locktime: this.getLockTime(),
1613
+ keysInfo: __classPrivateFieldGet(this, _Output_expansionMap, "f") ? Object.values(__classPrivateFieldGet(this, _Output_expansionMap, "f")) : [],
1614
+ scriptPubKey: this.getScriptPubKey(),
1615
+ isSegwit,
1616
+ witnessScript: this.getWitnessScript(),
1617
+ redeemScript: this.getRedeemScript(),
1618
+ rbf,
1619
+ Transaction
1620
+ });
1621
+ //The finalizer adds the unlocking script (scriptSig/scriptWitness) once
1622
+ //signatures are ready.
1623
+ const finalizer = ({ psbt, validate = true }) => {
1624
+ // Normalize to Psbt interface for finalization
1625
+ psbt = (0, psbt_1.toPsbt)(psbt);
1626
+ if (validate &&
1627
+ !psbt.validateSignaturesOfInput(index, signatureValidator)) {
1628
+ throw new Error(`Error: invalid signatures on input ${index}`);
1629
+ }
1630
+ //An index must be passed since finding the index in the psbt cannot be
1631
+ //done:
1632
+ //Imagine the case where you received money twice to
1633
+ //the same miniscript-based address. You would have the same scriptPubKey,
1634
+ //same sequences, ... The descriptor does not store the hash of the previous
1635
+ //transaction since it is a general Output instance. Indices must be kept
1636
+ //out of the scope of this class and then passed.
1637
+ __classPrivateFieldGet(this, _Output_instances, "m", _Output_assertPsbtInput).call(this, { index, psbt });
1638
+ if (__classPrivateFieldGet(this, _Output_isTaproot, "f") &&
1639
+ __classPrivateFieldGet(this, _Output_taprootSpendPath, "f") === 'script' &&
1640
+ !__classPrivateFieldGet(this, _Output_tapTreeInfo, "f"))
1641
+ throw new Error(`Error: taprootSpendPath=script requires taproot tree info`);
1642
+ if (__classPrivateFieldGet(this, _Output_tapTreeInfo, "f") && __classPrivateFieldGet(this, _Output_taprootSpendPath, "f") === 'script') {
1643
+ const input = psbt.data.inputs[index];
1644
+ const tapLeafScript = input?.tapLeafScript;
1645
+ if (!tapLeafScript || tapLeafScript.length === 0)
1646
+ throw new Error(`Error: cannot finalize taproot script-path without tapLeafScript`);
1647
+ const tapScriptSig = input?.tapScriptSig;
1648
+ if (!tapScriptSig || tapScriptSig.length === 0)
1649
+ throw new Error(`Error: cannot finalize taproot script-path without tapScriptSig`);
1650
+ const taprootSatisfaction = this.getTapScriptSatisfaction(tapScriptSig);
1651
+ const matchingLeaf = tapLeafScript.find(leafScript => (0, uint8array_tools_1.compare)((0, bitcoinjs_lib_internals_1.tapleafHash)({
1652
+ output: leafScript.script,
1653
+ version: leafScript.leafVersion
1654
+ }), taprootSatisfaction.tapLeafHash) === 0);
1655
+ if (!matchingLeaf)
1656
+ throw new Error(`Error: tapLeafScript does not match planned tapLeafHash`);
1657
+ if ((0, uint8array_tools_1.compare)(matchingLeaf.script, taprootSatisfaction.leaf.tapScript) !==
1658
+ 0 ||
1659
+ matchingLeaf.leafVersion !== taprootSatisfaction.leaf.version)
1660
+ throw new Error(`Error: tapLeafScript does not match planned leaf script`);
1661
+ const witness = [
1662
+ ...taprootSatisfaction.stackItems,
1663
+ matchingLeaf.script,
1664
+ matchingLeaf.controlBlock
1665
+ ];
1666
+ const finalScriptWitness = (0, bitcoinjs_lib_internals_1.witnessStackToScriptWitness)(witness);
1667
+ psbt.finalizeTaprootInput(index, undefined, () => ({
1668
+ finalScriptWitness
1669
+ }));
1670
+ }
1671
+ else if (!__classPrivateFieldGet(this, _Output_miniscript, "f")) {
1672
+ //Use standard finalizers
1673
+ psbt.finalizeInput(index);
1674
+ }
1675
+ else {
1676
+ const signatures = psbt.data.inputs[index]?.partialSig;
1677
+ if (!signatures)
1678
+ throw new Error(`Error: cannot finalize without signatures`);
1679
+ const { scriptSatisfaction } = this.getScriptSatisfaction(signatures);
1680
+ psbt.finalizeInput(index, (0, psbt_1.finalScriptsFuncFactory)(scriptSatisfaction, __classPrivateFieldGet(this, _Output_network, "f"), payments));
1681
+ }
1682
+ };
1683
+ return finalizer;
1684
+ }
1685
+ /**
1686
+ * Adds this output as an output of the provided `psbt` with the given
1687
+ * value.
1688
+ * @param params - The parameters for the method.
1689
+ * @param params.psbt - Either a
1690
+ * {@link https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/ts_src/psbt.ts | bitcoinjs-lib `Psbt`}
1691
+ * or a {@link https://github.com/paulmillr/scure-btc-signer | `@scure/btc-signer` `Transaction`}.
1692
+ * @param params.value - The value for the output in satoshis.
1693
+ */
1694
+ updatePsbtAsOutput({ psbt, value }) {
1695
+ if (typeof value !== 'bigint')
1696
+ throw new Error(`Error: value must be a bigint`);
1697
+ if (value < 0n)
1698
+ throw new Error(`Error: value must be >= 0n`);
1699
+ // Normalize to Psbt interface
1700
+ psbt = (0, psbt_1.toPsbt)(psbt);
1701
+ psbt.addOutput({ script: this.getScriptPubKey(), value });
1702
+ }
1703
+ /**
1704
+ * Decomposes the descriptor used to form this `Output` into its elemental
1705
+ * parts. See {@link ExpansionMap ExpansionMap} for a detailed explanation.
1706
+ */
1707
+ expand() {
1708
+ return {
1709
+ ...(__classPrivateFieldGet(this, _Output_expandedExpression, "f") !== undefined
1710
+ ? { expandedExpression: __classPrivateFieldGet(this, _Output_expandedExpression, "f") }
1711
+ : {}),
1712
+ ...(__classPrivateFieldGet(this, _Output_miniscript, "f") !== undefined
1713
+ ? { miniscript: __classPrivateFieldGet(this, _Output_miniscript, "f") }
1714
+ : {}),
1715
+ ...(__classPrivateFieldGet(this, _Output_expandedMiniscript, "f") !== undefined
1716
+ ? { expandedMiniscript: __classPrivateFieldGet(this, _Output_expandedMiniscript, "f") }
1717
+ : {}),
1718
+ ...(__classPrivateFieldGet(this, _Output_tapTreeExpression, "f") !== undefined
1719
+ ? { tapTreeExpression: __classPrivateFieldGet(this, _Output_tapTreeExpression, "f") }
1720
+ : {}),
1721
+ ...(__classPrivateFieldGet(this, _Output_tapTree, "f") !== undefined ? { tapTree: __classPrivateFieldGet(this, _Output_tapTree, "f") } : {}),
1722
+ ...(__classPrivateFieldGet(this, _Output_tapTreeInfo, "f") !== undefined
1723
+ ? { tapTreeInfo: __classPrivateFieldGet(this, _Output_tapTreeInfo, "f") }
1724
+ : {}),
1725
+ ...(__classPrivateFieldGet(this, _Output_expansionMap, "f") !== undefined
1726
+ ? { expansionMap: __classPrivateFieldGet(this, _Output_expansionMap, "f") }
1727
+ : {})
1728
+ };
1729
+ }
1730
+ }
1731
+ _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_isTaproot = new WeakMap(), _Output_expandedExpression = new WeakMap(), _Output_expandedMiniscript = new WeakMap(), _Output_tapTreeExpression = new WeakMap(), _Output_tapTree = new WeakMap(), _Output_tapTreeInfo = new WeakMap(), _Output_taprootSpendPath = new WeakMap(), _Output_tapLeaf = new WeakMap(), _Output_expansionMap = new WeakMap(), _Output_network = new WeakMap(), _Output_instances = new WeakSet(), _Output_resolveMiniscriptSignersPubKeys = function _Output_resolveMiniscriptSignersPubKeys() {
1732
+ //If the user did not provide a pubkey subset (signersPubKeys), assume all
1733
+ //miniscript pubkeys can sign.
1734
+ if (__classPrivateFieldGet(this, _Output_signersPubKeys, "f"))
1735
+ return __classPrivateFieldGet(this, _Output_signersPubKeys, "f");
1736
+ const expansionMap = __classPrivateFieldGet(this, _Output_expansionMap, "f");
1737
+ if (!expansionMap)
1738
+ throw new Error(`Error: expansionMap not available for miniscript`);
1739
+ return Object.values(expansionMap).map(keyInfo => {
1740
+ const pubkey = keyInfo.pubkey;
1741
+ if (!pubkey)
1742
+ throw new Error(`Error: miniscript key missing pubkey`);
1743
+ return pubkey;
1744
+ });
1745
+ }, _Output_assertMiniscriptSatisfactionResourceLimits = function _Output_assertMiniscriptSatisfactionResourceLimits(scriptSatisfaction) {
1746
+ if (!__classPrivateFieldGet(this, _Output_miniscript, "f"))
1747
+ return;
1748
+ const satisfactionStackItems = scriptLib.toStack(scriptSatisfaction);
1749
+ // For wsh(...) and sh(wsh(...)), enforce witness stack limits.
1750
+ if (__classPrivateFieldGet(this, _Output_isSegwit, "f") && !__classPrivateFieldGet(this, _Output_isTaproot, "f")) {
1751
+ (0, resourceLimits_1.assertWitnessV0SatisfactionResourceLimits)({
1752
+ stackItems: satisfactionStackItems
1753
+ });
1754
+ return;
1755
+ }
1756
+ if (!__classPrivateFieldGet(this, _Output_isSegwit, "f")) {
1757
+ // In legacy P2SH, after scriptSig execution, the stack is:
1758
+ // [ ...satisfactionStackItems, redeemScript ]
1759
+ // Consensus limits apply here: each element must be <= 520 bytes and total
1760
+ // stack items must be <= 1000.
1761
+ // redeemScript size is already validated during script construction
1762
+ // to fail early (look for MAX_SCRIPT_ELEMENT_SIZE checks in this file).
1763
+ // Below we re-validate again the redeemScript + the rest of stack items.
1764
+ const redeemScript = __classPrivateFieldGet(this, _Output_redeemScript, "f");
1765
+ if (!redeemScript)
1766
+ throw new Error(`Error: redeemScript not available for P2SH spend`);
1767
+ (0, resourceLimits_1.assertConsensusStackResourceLimits)({
1768
+ stackItems: [...satisfactionStackItems, redeemScript]
1769
+ });
1770
+ (0, resourceLimits_1.assertP2shScriptSigStandardSize)({
1771
+ scriptSatisfaction,
1772
+ redeemScript,
1773
+ network: __classPrivateFieldGet(this, _Output_network, "f"),
1774
+ payments
1775
+ });
1776
+ }
1777
+ }, _Output_resolveTapTreeSignersPubKeys = function _Output_resolveTapTreeSignersPubKeys() {
1778
+ //If the user did not provide a pubkey subset (signersPubKeys), assume all
1779
+ //taproot leaf pubkeys can sign.
1780
+ const tapTreeInfo = __classPrivateFieldGet(this, _Output_tapTreeInfo, "f");
1781
+ if (!tapTreeInfo)
1782
+ throw new Error(`Error: taproot tree info not available`);
1783
+ const candidatePubkeys = __classPrivateFieldGet(this, _Output_signersPubKeys, "f")
1784
+ ? __classPrivateFieldGet(this, _Output_signersPubKeys, "f").map(tapMiniscript_1.normalizeTaprootPubkey)
1785
+ : (0, tapMiniscript_1.collectTapTreePubkeys)(tapTreeInfo);
1786
+ return Array.from(new Set(candidatePubkeys.map(pubkey => (0, uint8array_tools_1.toHex)(pubkey)))).map(hex => (0, uint8array_tools_1.fromHex)(hex));
1787
+ }, _Output_getConstraints = function _Output_getConstraints() {
1788
+ const miniscript = __classPrivateFieldGet(this, _Output_miniscript, "f");
1789
+ const preimages = __classPrivateFieldGet(this, _Output_preimages, "f");
1790
+ const expandedMiniscript = __classPrivateFieldGet(this, _Output_expandedMiniscript, "f");
1791
+ const expansionMap = __classPrivateFieldGet(this, _Output_expansionMap, "f");
1792
+ const tapTreeInfo = __classPrivateFieldGet(this, _Output_tapTreeInfo, "f");
1793
+ //Create a method. solvePreimages to solve them.
1794
+ if (miniscript) {
1795
+ if (expandedMiniscript === undefined || expansionMap === undefined)
1796
+ throw new Error(`Error: cannot get time constraints from not expanded miniscript ${miniscript}`);
1797
+ //We create some fakeSignatures since we may not have them yet.
1798
+ //We only want to retrieve the nLockTime and nSequence of the satisfaction and
1799
+ //signatures don't matter
1800
+ const fakeSignatures = __classPrivateFieldGet(this, _Output_instances, "m", _Output_resolveMiniscriptSignersPubKeys).call(this).map(pubkey => ({
1801
+ pubkey,
1802
+ signature: new Uint8Array(ECDSA_FAKE_SIGNATURE_SIZE)
1803
+ }));
1804
+ const satisfaction = (0, miniscript_1.satisfyMiniscript)({
1805
+ expandedMiniscript,
1806
+ expansionMap,
1807
+ signatures: fakeSignatures,
1808
+ preimages,
1809
+ scriptLib
1810
+ });
1811
+ __classPrivateFieldGet(this, _Output_instances, "m", _Output_assertMiniscriptSatisfactionResourceLimits).call(this, satisfaction.scriptSatisfaction);
1812
+ const { nLockTime, nSequence } = satisfaction;
1813
+ return { nLockTime, nSequence, tapLeafHash: undefined };
1814
+ }
1815
+ else if (tapTreeInfo && __classPrivateFieldGet(this, _Output_taprootSpendPath, "f") === 'script') {
1816
+ const fakeSignatures = __classPrivateFieldGet(this, _Output_instances, "m", _Output_resolveTapTreeSignersPubKeys).call(this).map(pubkey => ({
1817
+ pubkey,
1818
+ signature: new Uint8Array(TAPROOT_FAKE_SIGNATURE_SIZE)
1819
+ }));
1820
+ const { nLockTime, nSequence, tapLeafHash } = (0, tapMiniscript_1.satisfyTapTree)({
1821
+ tapTreeInfo,
1822
+ preimages: __classPrivateFieldGet(this, _Output_preimages, "f"),
1823
+ signatures: fakeSignatures,
1824
+ ...(__classPrivateFieldGet(this, _Output_tapLeaf, "f") !== undefined ? { tapLeaf: __classPrivateFieldGet(this, _Output_tapLeaf, "f") } : {}),
1825
+ scriptLib
1826
+ });
1827
+ return { nLockTime, nSequence, tapLeafHash };
1828
+ }
1829
+ return undefined;
1830
+ }, _Output_assertPsbtInput = function _Output_assertPsbtInput({ psbt, index }) {
1831
+ // Normalize to Psbt interface
1832
+ psbt = (0, psbt_1.toPsbt)(psbt);
1833
+ const input = psbt.data.inputs[index];
1834
+ const txInput = psbt.txInputs[index];
1835
+ if (!input || !txInput)
1836
+ throw new Error(`Error: invalid input or txInput`);
1837
+ const { sequence: inputSequence, index: vout } = txInput;
1838
+ let scriptPubKey;
1839
+ if (input.witnessUtxo)
1840
+ scriptPubKey = input.witnessUtxo.script;
1841
+ else {
1842
+ if (!input.nonWitnessUtxo)
1843
+ throw new Error(`Error: input should have either witnessUtxo or nonWitnessUtxo`);
1844
+ const tx = Transaction.fromBuffer(input.nonWitnessUtxo);
1845
+ const out = tx.outs[vout];
1846
+ if (!out)
1847
+ throw new Error(`Error: utxo should exist`);
1848
+ scriptPubKey = out.script;
1849
+ }
1850
+ const locktime = this.getLockTime() || 0;
1851
+ const sequence = this.getSequence();
1852
+ //We don't know whether the user opted for RBF or not. So check that
1853
+ //at least one of the 2 sequences matches.
1854
+ const sequenceNoRBF = sequence !== undefined
1855
+ ? sequence
1856
+ : locktime === 0
1857
+ ? 0xffffffff
1858
+ : 0xfffffffe;
1859
+ const sequenceRBF = sequence !== undefined ? sequence : 0xfffffffd;
1860
+ const eqBytes = (bytes1, bytes2) => bytes1 === undefined || bytes2 === undefined
1861
+ ? bytes1 === bytes2
1862
+ : (0, uint8array_tools_1.compare)(bytes1, bytes2) === 0;
1863
+ if ((0, uint8array_tools_1.compare)(scriptPubKey, this.getScriptPubKey()) !== 0 ||
1864
+ (sequenceRBF !== inputSequence && sequenceNoRBF !== inputSequence) ||
1865
+ locktime !== psbt.locktime ||
1866
+ !eqBytes(this.getWitnessScript(), input.witnessScript) ||
1867
+ !eqBytes(this.getRedeemScript(), input.redeemScript)) {
1868
+ throw new Error(`Error: cannot finalize psbt index ${index} since it does not correspond to this descriptor`);
1869
+ }
1870
+ };
1871
+ const nativeKeys = isBitcoinJsLib(bitcoinLib);
1872
+ return {
1873
+ Output,
1874
+ parseKeyExpression,
1875
+ expand,
1876
+ ECPair: nativeKeys
1877
+ ? // Expose full ECPairAPI typing only with native bitcoinjs adapter.
1878
+ // In this branch ECPair comes from the real 'ecpair' package.
1879
+ ECPair
1880
+ : // Non-bitcoinjs adapters only implement the subset used internally.
1881
+ // Expose a throwing proxy to prevent accidental external usage.
1882
+ unsupportedKeyApi('ECPair'),
1883
+ // Same behavior for BIP32: full API only for native bitcoinjs adapter.
1884
+ BIP32: nativeKeys
1885
+ ? BIP32
1886
+ : unsupportedKeyApi('BIP32')
1887
+ };
1888
+ }