UNPKG

55.2 kBJavaScriptView Raw
1'use strict';
2Object.defineProperty(exports, '__esModule', { value: true });
3exports.Psbt = void 0;
4const bip174_1 = require('bip174');
5const varuint = require('bip174/src/lib/converter/varint');
6const utils_1 = require('bip174/src/lib/utils');
7const address_1 = require('./address');
8const bufferutils_1 = require('./bufferutils');
9const networks_1 = require('./networks');
10const payments = require('./payments');
11const bip341_1 = require('./payments/bip341');
12const bscript = require('./script');
13const transaction_1 = require('./transaction');
14const bip371_1 = require('./psbt/bip371');
15const psbtutils_1 = require('./psbt/psbtutils');
16/**
17 * These are the default arguments for a Psbt instance.
18 */
19const DEFAULT_OPTS = {
20 /**
21 * A bitcoinjs Network object. This is only used if you pass an `address`
22 * parameter to addOutput. Otherwise it is not needed and can be left default.
23 */
24 network: networks_1.bitcoin,
25 /**
26 * When extractTransaction is called, the fee rate is checked.
27 * THIS IS NOT TO BE RELIED ON.
28 * It is only here as a last ditch effort to prevent sending a 500 BTC fee etc.
29 */
30 maximumFeeRate: 5000, // satoshi per byte
31};
32/**
33 * Psbt class can parse and generate a PSBT binary based off of the BIP174.
34 * There are 6 roles that this class fulfills. (Explained in BIP174)
35 *
36 * Creator: This can be done with `new Psbt()`
37 * Updater: This can be done with `psbt.addInput(input)`, `psbt.addInputs(inputs)`,
38 * `psbt.addOutput(output)`, `psbt.addOutputs(outputs)` when you are looking to
39 * add new inputs and outputs to the PSBT, and `psbt.updateGlobal(itemObject)`,
40 * `psbt.updateInput(itemObject)`, `psbt.updateOutput(itemObject)`
41 * addInput requires hash: Buffer | string; and index: number; as attributes
42 * and can also include any attributes that are used in updateInput method.
43 * addOutput requires script: Buffer; and value: number; and likewise can include
44 * data for updateOutput.
45 * For a list of what attributes should be what types. Check the bip174 library.
46 * Also, check the integration tests for some examples of usage.
47 * Signer: There are a few methods. signAllInputs and signAllInputsAsync, which will search all input
48 * information for your pubkey or pubkeyhash, and only sign inputs where it finds
49 * your info. Or you can explicitly sign a specific input with signInput and
50 * signInputAsync. For the async methods you can create a SignerAsync object
51 * and use something like a hardware wallet to sign with. (You must implement this)
52 * Combiner: psbts can be combined easily with `psbt.combine(psbt2, psbt3, psbt4 ...)`
53 * the psbt calling combine will always have precedence when a conflict occurs.
54 * Combine checks if the internal bitcoin transaction is the same, so be sure that
55 * all sequences, version, locktime, etc. are the same before combining.
56 * Input Finalizer: This role is fairly important. Not only does it need to construct
57 * the input scriptSigs and witnesses, but it SHOULD verify the signatures etc.
58 * Before running `psbt.finalizeAllInputs()` please run `psbt.validateSignaturesOfAllInputs()`
59 * Running any finalize method will delete any data in the input(s) that are no longer
60 * needed due to the finalized scripts containing the information.
61 * Transaction Extractor: This role will perform some checks before returning a
62 * Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
63 */
64class Psbt {
65 static fromBase64(data, opts = {}) {
66 const buffer = Buffer.from(data, 'base64');
67 return this.fromBuffer(buffer, opts);
68 }
69 static fromHex(data, opts = {}) {
70 const buffer = Buffer.from(data, 'hex');
71 return this.fromBuffer(buffer, opts);
72 }
73 static fromBuffer(buffer, opts = {}) {
74 const psbtBase = bip174_1.Psbt.fromBuffer(buffer, transactionFromBuffer);
75 const psbt = new Psbt(opts, psbtBase);
76 checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
77 return psbt;
78 }
79 constructor(opts = {}, data = new bip174_1.Psbt(new PsbtTransaction())) {
80 this.data = data;
81 // set defaults
82 this.opts = Object.assign({}, DEFAULT_OPTS, opts);
83 this.__CACHE = {
84 __NON_WITNESS_UTXO_TX_CACHE: [],
85 __NON_WITNESS_UTXO_BUF_CACHE: [],
86 __TX_IN_CACHE: {},
87 __TX: this.data.globalMap.unsignedTx.tx,
88 // Psbt's predecesor (TransactionBuilder - now removed) behavior
89 // was to not confirm input values before signing.
90 // Even though we highly encourage people to get
91 // the full parent transaction to verify values, the ability to
92 // sign non-segwit inputs without the full transaction was often
93 // requested. So the only way to activate is to use @ts-ignore.
94 // We will disable exporting the Psbt when unsafe sign is active.
95 // because it is not BIP174 compliant.
96 __UNSAFE_SIGN_NONSEGWIT: false,
97 };
98 if (this.data.inputs.length === 0) this.setVersion(2);
99 // Make data hidden when enumerating
100 const dpew = (obj, attr, enumerable, writable) =>
101 Object.defineProperty(obj, attr, {
102 enumerable,
103 writable,
104 });
105 dpew(this, '__CACHE', false, true);
106 dpew(this, 'opts', false, true);
107 }
108 get inputCount() {
109 return this.data.inputs.length;
110 }
111 get version() {
112 return this.__CACHE.__TX.version;
113 }
114 set version(version) {
115 this.setVersion(version);
116 }
117 get locktime() {
118 return this.__CACHE.__TX.locktime;
119 }
120 set locktime(locktime) {
121 this.setLocktime(locktime);
122 }
123 get txInputs() {
124 return this.__CACHE.__TX.ins.map(input => ({
125 hash: (0, bufferutils_1.cloneBuffer)(input.hash),
126 index: input.index,
127 sequence: input.sequence,
128 }));
129 }
130 get txOutputs() {
131 return this.__CACHE.__TX.outs.map(output => {
132 let address;
133 try {
134 address = (0, address_1.fromOutputScript)(
135 output.script,
136 this.opts.network,
137 );
138 } catch (_) {}
139 return {
140 script: (0, bufferutils_1.cloneBuffer)(output.script),
141 value: output.value,
142 address,
143 };
144 });
145 }
146 combine(...those) {
147 this.data.combine(...those.map(o => o.data));
148 return this;
149 }
150 clone() {
151 // TODO: more efficient cloning
152 const res = Psbt.fromBuffer(this.data.toBuffer());
153 res.opts = JSON.parse(JSON.stringify(this.opts));
154 return res;
155 }
156 setMaximumFeeRate(satoshiPerByte) {
157 check32Bit(satoshiPerByte); // 42.9 BTC per byte IS excessive... so throw
158 this.opts.maximumFeeRate = satoshiPerByte;
159 }
160 setVersion(version) {
161 check32Bit(version);
162 checkInputsForPartialSig(this.data.inputs, 'setVersion');
163 const c = this.__CACHE;
164 c.__TX.version = version;
165 c.__EXTRACTED_TX = undefined;
166 return this;
167 }
168 setLocktime(locktime) {
169 check32Bit(locktime);
170 checkInputsForPartialSig(this.data.inputs, 'setLocktime');
171 const c = this.__CACHE;
172 c.__TX.locktime = locktime;
173 c.__EXTRACTED_TX = undefined;
174 return this;
175 }
176 setInputSequence(inputIndex, sequence) {
177 check32Bit(sequence);
178 checkInputsForPartialSig(this.data.inputs, 'setInputSequence');
179 const c = this.__CACHE;
180 if (c.__TX.ins.length <= inputIndex) {
181 throw new Error('Input index too high');
182 }
183 c.__TX.ins[inputIndex].sequence = sequence;
184 c.__EXTRACTED_TX = undefined;
185 return this;
186 }
187 addInputs(inputDatas) {
188 inputDatas.forEach(inputData => this.addInput(inputData));
189 return this;
190 }
191 addInput(inputData) {
192 if (
193 arguments.length > 1 ||
194 !inputData ||
195 inputData.hash === undefined ||
196 inputData.index === undefined
197 ) {
198 throw new Error(
199 `Invalid arguments for Psbt.addInput. ` +
200 `Requires single object with at least [hash] and [index]`,
201 );
202 }
203 (0, bip371_1.checkTaprootInputFields)(inputData, inputData, 'addInput');
204 checkInputsForPartialSig(this.data.inputs, 'addInput');
205 if (inputData.witnessScript) checkInvalidP2WSH(inputData.witnessScript);
206 const c = this.__CACHE;
207 this.data.addInput(inputData);
208 const txIn = c.__TX.ins[c.__TX.ins.length - 1];
209 checkTxInputCache(c, txIn);
210 const inputIndex = this.data.inputs.length - 1;
211 const input = this.data.inputs[inputIndex];
212 if (input.nonWitnessUtxo) {
213 addNonWitnessTxCache(this.__CACHE, input, inputIndex);
214 }
215 c.__FEE = undefined;
216 c.__FEE_RATE = undefined;
217 c.__EXTRACTED_TX = undefined;
218 return this;
219 }
220 addOutputs(outputDatas) {
221 outputDatas.forEach(outputData => this.addOutput(outputData));
222 return this;
223 }
224 addOutput(outputData) {
225 if (
226 arguments.length > 1 ||
227 !outputData ||
228 outputData.value === undefined ||
229 (outputData.address === undefined && outputData.script === undefined)
230 ) {
231 throw new Error(
232 `Invalid arguments for Psbt.addOutput. ` +
233 `Requires single object with at least [script or address] and [value]`,
234 );
235 }
236 checkInputsForPartialSig(this.data.inputs, 'addOutput');
237 const { address } = outputData;
238 if (typeof address === 'string') {
239 const { network } = this.opts;
240 const script = (0, address_1.toOutputScript)(address, network);
241 outputData = Object.assign(outputData, { script });
242 }
243 (0, bip371_1.checkTaprootOutputFields)(outputData, outputData, 'addOutput');
244 const c = this.__CACHE;
245 this.data.addOutput(outputData);
246 c.__FEE = undefined;
247 c.__FEE_RATE = undefined;
248 c.__EXTRACTED_TX = undefined;
249 return this;
250 }
251 extractTransaction(disableFeeCheck) {
252 if (!this.data.inputs.every(isFinalized)) throw new Error('Not finalized');
253 const c = this.__CACHE;
254 if (!disableFeeCheck) {
255 checkFees(this, c, this.opts);
256 }
257 if (c.__EXTRACTED_TX) return c.__EXTRACTED_TX;
258 const tx = c.__TX.clone();
259 inputFinalizeGetAmts(this.data.inputs, tx, c, true);
260 return tx;
261 }
262 getFeeRate() {
263 return getTxCacheValue(
264 '__FEE_RATE',
265 'fee rate',
266 this.data.inputs,
267 this.__CACHE,
268 );
269 }
270 getFee() {
271 return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE);
272 }
273 finalizeAllInputs() {
274 (0, utils_1.checkForInput)(this.data.inputs, 0); // making sure we have at least one
275 range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx));
276 return this;
277 }
278 finalizeInput(inputIndex, finalScriptsFunc) {
279 const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
280 if ((0, bip371_1.isTaprootInput)(input))
281 return this._finalizeTaprootInput(
282 inputIndex,
283 input,
284 undefined,
285 finalScriptsFunc,
286 );
287 return this._finalizeInput(inputIndex, input, finalScriptsFunc);
288 }
289 finalizeTaprootInput(
290 inputIndex,
291 tapLeafHashToFinalize,
292 finalScriptsFunc = bip371_1.tapScriptFinalizer,
293 ) {
294 const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
295 if ((0, bip371_1.isTaprootInput)(input))
296 return this._finalizeTaprootInput(
297 inputIndex,
298 input,
299 tapLeafHashToFinalize,
300 finalScriptsFunc,
301 );
302 throw new Error(`Cannot finalize input #${inputIndex}. Not Taproot.`);
303 }
304 _finalizeInput(inputIndex, input, finalScriptsFunc = getFinalScripts) {
305 const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
306 inputIndex,
307 input,
308 this.__CACHE,
309 );
310 if (!script) throw new Error(`No script found for input #${inputIndex}`);
311 checkPartialSigSighashes(input);
312 const { finalScriptSig, finalScriptWitness } = finalScriptsFunc(
313 inputIndex,
314 input,
315 script,
316 isSegwit,
317 isP2SH,
318 isP2WSH,
319 );
320 if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
321 if (finalScriptWitness)
322 this.data.updateInput(inputIndex, { finalScriptWitness });
323 if (!finalScriptSig && !finalScriptWitness)
324 throw new Error(`Unknown error finalizing input #${inputIndex}`);
325 this.data.clearFinalizedInput(inputIndex);
326 return this;
327 }
328 _finalizeTaprootInput(
329 inputIndex,
330 input,
331 tapLeafHashToFinalize,
332 finalScriptsFunc = bip371_1.tapScriptFinalizer,
333 ) {
334 if (!input.witnessUtxo)
335 throw new Error(
336 `Cannot finalize input #${inputIndex}. Missing withness utxo.`,
337 );
338 // Check key spend first. Increased privacy and reduced block space.
339 if (input.tapKeySig) {
340 const payment = payments.p2tr({
341 output: input.witnessUtxo.script,
342 signature: input.tapKeySig,
343 });
344 const finalScriptWitness = (0, psbtutils_1.witnessStackToScriptWitness)(
345 payment.witness,
346 );
347 this.data.updateInput(inputIndex, { finalScriptWitness });
348 } else {
349 const { finalScriptWitness } = finalScriptsFunc(
350 inputIndex,
351 input,
352 tapLeafHashToFinalize,
353 );
354 this.data.updateInput(inputIndex, { finalScriptWitness });
355 }
356 this.data.clearFinalizedInput(inputIndex);
357 return this;
358 }
359 getInputType(inputIndex) {
360 const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
361 const script = getScriptFromUtxo(inputIndex, input, this.__CACHE);
362 const result = getMeaningfulScript(
363 script,
364 inputIndex,
365 'input',
366 input.redeemScript || redeemFromFinalScriptSig(input.finalScriptSig),
367 input.witnessScript ||
368 redeemFromFinalWitnessScript(input.finalScriptWitness),
369 );
370 const type = result.type === 'raw' ? '' : result.type + '-';
371 const mainType = classifyScript(result.meaningfulScript);
372 return type + mainType;
373 }
374 inputHasPubkey(inputIndex, pubkey) {
375 const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
376 return pubkeyInInput(pubkey, input, inputIndex, this.__CACHE);
377 }
378 inputHasHDKey(inputIndex, root) {
379 const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
380 const derivationIsMine = bip32DerivationIsMine(root);
381 return (
382 !!input.bip32Derivation && input.bip32Derivation.some(derivationIsMine)
383 );
384 }
385 outputHasPubkey(outputIndex, pubkey) {
386 const output = (0, utils_1.checkForOutput)(this.data.outputs, outputIndex);
387 return pubkeyInOutput(pubkey, output, outputIndex, this.__CACHE);
388 }
389 outputHasHDKey(outputIndex, root) {
390 const output = (0, utils_1.checkForOutput)(this.data.outputs, outputIndex);
391 const derivationIsMine = bip32DerivationIsMine(root);
392 return (
393 !!output.bip32Derivation && output.bip32Derivation.some(derivationIsMine)
394 );
395 }
396 validateSignaturesOfAllInputs(validator) {
397 (0, utils_1.checkForInput)(this.data.inputs, 0); // making sure we have at least one
398 const results = range(this.data.inputs.length).map(idx =>
399 this.validateSignaturesOfInput(idx, validator),
400 );
401 return results.reduce((final, res) => res === true && final, true);
402 }
403 validateSignaturesOfInput(inputIndex, validator, pubkey) {
404 const input = this.data.inputs[inputIndex];
405 if ((0, bip371_1.isTaprootInput)(input))
406 return this.validateSignaturesOfTaprootInput(
407 inputIndex,
408 validator,
409 pubkey,
410 );
411 return this._validateSignaturesOfInput(inputIndex, validator, pubkey);
412 }
413 _validateSignaturesOfInput(inputIndex, validator, pubkey) {
414 const input = this.data.inputs[inputIndex];
415 const partialSig = (input || {}).partialSig;
416 if (!input || !partialSig || partialSig.length < 1)
417 throw new Error('No signatures to validate');
418 if (typeof validator !== 'function')
419 throw new Error('Need validator function to validate signatures');
420 const mySigs = pubkey
421 ? partialSig.filter(sig => sig.pubkey.equals(pubkey))
422 : partialSig;
423 if (mySigs.length < 1) throw new Error('No signatures for this pubkey');
424 const results = [];
425 let hashCache;
426 let scriptCache;
427 let sighashCache;
428 for (const pSig of mySigs) {
429 const sig = bscript.signature.decode(pSig.signature);
430 const { hash, script } =
431 sighashCache !== sig.hashType
432 ? getHashForSig(
433 inputIndex,
434 Object.assign({}, input, { sighashType: sig.hashType }),
435 this.__CACHE,
436 true,
437 )
438 : { hash: hashCache, script: scriptCache };
439 sighashCache = sig.hashType;
440 hashCache = hash;
441 scriptCache = script;
442 checkScriptForPubkey(pSig.pubkey, script, 'verify');
443 results.push(validator(pSig.pubkey, hash, sig.signature));
444 }
445 return results.every(res => res === true);
446 }
447 validateSignaturesOfTaprootInput(inputIndex, validator, pubkey) {
448 const input = this.data.inputs[inputIndex];
449 const tapKeySig = (input || {}).tapKeySig;
450 const tapScriptSig = (input || {}).tapScriptSig;
451 if (!input && !tapKeySig && !(tapScriptSig && !tapScriptSig.length))
452 throw new Error('No signatures to validate');
453 if (typeof validator !== 'function')
454 throw new Error('Need validator function to validate signatures');
455 pubkey = pubkey && (0, bip371_1.toXOnly)(pubkey);
456 const allHashses = pubkey
457 ? getTaprootHashesForSig(
458 inputIndex,
459 input,
460 this.data.inputs,
461 pubkey,
462 this.__CACHE,
463 )
464 : getAllTaprootHashesForSig(
465 inputIndex,
466 input,
467 this.data.inputs,
468 this.__CACHE,
469 );
470 if (!allHashses.length) throw new Error('No signatures for this pubkey');
471 const tapKeyHash = allHashses.find(h => !h.leafHash);
472 let validationResultCount = 0;
473 if (tapKeySig && tapKeyHash) {
474 const isValidTapkeySig = validator(
475 tapKeyHash.pubkey,
476 tapKeyHash.hash,
477 trimTaprootSig(tapKeySig),
478 );
479 if (!isValidTapkeySig) return false;
480 validationResultCount++;
481 }
482 if (tapScriptSig) {
483 for (const tapSig of tapScriptSig) {
484 const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey));
485 if (tapSigHash) {
486 const isValidTapScriptSig = validator(
487 tapSig.pubkey,
488 tapSigHash.hash,
489 trimTaprootSig(tapSig.signature),
490 );
491 if (!isValidTapScriptSig) return false;
492 validationResultCount++;
493 }
494 }
495 }
496 return validationResultCount > 0;
497 }
498 signAllInputsHD(
499 hdKeyPair,
500 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
501 ) {
502 if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
503 throw new Error('Need HDSigner to sign input');
504 }
505 const results = [];
506 for (const i of range(this.data.inputs.length)) {
507 try {
508 this.signInputHD(i, hdKeyPair, sighashTypes);
509 results.push(true);
510 } catch (err) {
511 results.push(false);
512 }
513 }
514 if (results.every(v => v === false)) {
515 throw new Error('No inputs were signed');
516 }
517 return this;
518 }
519 signAllInputsHDAsync(
520 hdKeyPair,
521 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
522 ) {
523 return new Promise((resolve, reject) => {
524 if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
525 return reject(new Error('Need HDSigner to sign input'));
526 }
527 const results = [];
528 const promises = [];
529 for (const i of range(this.data.inputs.length)) {
530 promises.push(
531 this.signInputHDAsync(i, hdKeyPair, sighashTypes).then(
532 () => {
533 results.push(true);
534 },
535 () => {
536 results.push(false);
537 },
538 ),
539 );
540 }
541 return Promise.all(promises).then(() => {
542 if (results.every(v => v === false)) {
543 return reject(new Error('No inputs were signed'));
544 }
545 resolve();
546 });
547 });
548 }
549 signInputHD(
550 inputIndex,
551 hdKeyPair,
552 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
553 ) {
554 if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
555 throw new Error('Need HDSigner to sign input');
556 }
557 const signers = getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair);
558 signers.forEach(signer => this.signInput(inputIndex, signer, sighashTypes));
559 return this;
560 }
561 signInputHDAsync(
562 inputIndex,
563 hdKeyPair,
564 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
565 ) {
566 return new Promise((resolve, reject) => {
567 if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
568 return reject(new Error('Need HDSigner to sign input'));
569 }
570 const signers = getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair);
571 const promises = signers.map(signer =>
572 this.signInputAsync(inputIndex, signer, sighashTypes),
573 );
574 return Promise.all(promises)
575 .then(() => {
576 resolve();
577 })
578 .catch(reject);
579 });
580 }
581 signAllInputs(keyPair, sighashTypes) {
582 if (!keyPair || !keyPair.publicKey)
583 throw new Error('Need Signer to sign input');
584 // TODO: Add a pubkey/pubkeyhash cache to each input
585 // as input information is added, then eventually
586 // optimize this method.
587 const results = [];
588 for (const i of range(this.data.inputs.length)) {
589 try {
590 this.signInput(i, keyPair, sighashTypes);
591 results.push(true);
592 } catch (err) {
593 results.push(false);
594 }
595 }
596 if (results.every(v => v === false)) {
597 throw new Error('No inputs were signed');
598 }
599 return this;
600 }
601 signAllInputsAsync(keyPair, sighashTypes) {
602 return new Promise((resolve, reject) => {
603 if (!keyPair || !keyPair.publicKey)
604 return reject(new Error('Need Signer to sign input'));
605 // TODO: Add a pubkey/pubkeyhash cache to each input
606 // as input information is added, then eventually
607 // optimize this method.
608 const results = [];
609 const promises = [];
610 for (const [i] of this.data.inputs.entries()) {
611 promises.push(
612 this.signInputAsync(i, keyPair, sighashTypes).then(
613 () => {
614 results.push(true);
615 },
616 () => {
617 results.push(false);
618 },
619 ),
620 );
621 }
622 return Promise.all(promises).then(() => {
623 if (results.every(v => v === false)) {
624 return reject(new Error('No inputs were signed'));
625 }
626 resolve();
627 });
628 });
629 }
630 signInput(inputIndex, keyPair, sighashTypes) {
631 if (!keyPair || !keyPair.publicKey)
632 throw new Error('Need Signer to sign input');
633 const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
634 if ((0, bip371_1.isTaprootInput)(input)) {
635 return this._signTaprootInput(
636 inputIndex,
637 input,
638 keyPair,
639 undefined,
640 sighashTypes,
641 );
642 }
643 return this._signInput(inputIndex, keyPair, sighashTypes);
644 }
645 signTaprootInput(inputIndex, keyPair, tapLeafHashToSign, sighashTypes) {
646 if (!keyPair || !keyPair.publicKey)
647 throw new Error('Need Signer to sign input');
648 const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
649 if ((0, bip371_1.isTaprootInput)(input))
650 return this._signTaprootInput(
651 inputIndex,
652 input,
653 keyPair,
654 tapLeafHashToSign,
655 sighashTypes,
656 );
657 throw new Error(`Input #${inputIndex} is not of type Taproot.`);
658 }
659 _signInput(
660 inputIndex,
661 keyPair,
662 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
663 ) {
664 const { hash, sighashType } = getHashAndSighashType(
665 this.data.inputs,
666 inputIndex,
667 keyPair.publicKey,
668 this.__CACHE,
669 sighashTypes,
670 );
671 const partialSig = [
672 {
673 pubkey: keyPair.publicKey,
674 signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
675 },
676 ];
677 this.data.updateInput(inputIndex, { partialSig });
678 return this;
679 }
680 _signTaprootInput(
681 inputIndex,
682 input,
683 keyPair,
684 tapLeafHashToSign,
685 allowedSighashTypes = [transaction_1.Transaction.SIGHASH_DEFAULT],
686 ) {
687 const hashesForSig = this.checkTaprootHashesForSig(
688 inputIndex,
689 input,
690 keyPair,
691 tapLeafHashToSign,
692 allowedSighashTypes,
693 );
694 const tapKeySig = hashesForSig
695 .filter(h => !h.leafHash)
696 .map(h =>
697 (0, bip371_1.serializeTaprootSignature)(
698 keyPair.signSchnorr(h.hash),
699 input.sighashType,
700 ),
701 )[0];
702 const tapScriptSig = hashesForSig
703 .filter(h => !!h.leafHash)
704 .map(h => ({
705 pubkey: (0, bip371_1.toXOnly)(keyPair.publicKey),
706 signature: (0, bip371_1.serializeTaprootSignature)(
707 keyPair.signSchnorr(h.hash),
708 input.sighashType,
709 ),
710 leafHash: h.leafHash,
711 }));
712 if (tapKeySig) {
713 this.data.updateInput(inputIndex, { tapKeySig });
714 }
715 if (tapScriptSig.length) {
716 this.data.updateInput(inputIndex, { tapScriptSig });
717 }
718 return this;
719 }
720 signInputAsync(inputIndex, keyPair, sighashTypes) {
721 return Promise.resolve().then(() => {
722 if (!keyPair || !keyPair.publicKey)
723 throw new Error('Need Signer to sign input');
724 const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
725 if ((0, bip371_1.isTaprootInput)(input))
726 return this._signTaprootInputAsync(
727 inputIndex,
728 input,
729 keyPair,
730 undefined,
731 sighashTypes,
732 );
733 return this._signInputAsync(inputIndex, keyPair, sighashTypes);
734 });
735 }
736 signTaprootInputAsync(inputIndex, keyPair, tapLeafHash, sighashTypes) {
737 return Promise.resolve().then(() => {
738 if (!keyPair || !keyPair.publicKey)
739 throw new Error('Need Signer to sign input');
740 const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
741 if ((0, bip371_1.isTaprootInput)(input))
742 return this._signTaprootInputAsync(
743 inputIndex,
744 input,
745 keyPair,
746 tapLeafHash,
747 sighashTypes,
748 );
749 throw new Error(`Input #${inputIndex} is not of type Taproot.`);
750 });
751 }
752 _signInputAsync(
753 inputIndex,
754 keyPair,
755 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
756 ) {
757 const { hash, sighashType } = getHashAndSighashType(
758 this.data.inputs,
759 inputIndex,
760 keyPair.publicKey,
761 this.__CACHE,
762 sighashTypes,
763 );
764 return Promise.resolve(keyPair.sign(hash)).then(signature => {
765 const partialSig = [
766 {
767 pubkey: keyPair.publicKey,
768 signature: bscript.signature.encode(signature, sighashType),
769 },
770 ];
771 this.data.updateInput(inputIndex, { partialSig });
772 });
773 }
774 async _signTaprootInputAsync(
775 inputIndex,
776 input,
777 keyPair,
778 tapLeafHash,
779 sighashTypes = [transaction_1.Transaction.SIGHASH_DEFAULT],
780 ) {
781 const hashesForSig = this.checkTaprootHashesForSig(
782 inputIndex,
783 input,
784 keyPair,
785 tapLeafHash,
786 sighashTypes,
787 );
788 const signaturePromises = [];
789 const tapKeyHash = hashesForSig.filter(h => !h.leafHash)[0];
790 if (tapKeyHash) {
791 const tapKeySigPromise = Promise.resolve(
792 keyPair.signSchnorr(tapKeyHash.hash),
793 ).then(sig => {
794 return {
795 tapKeySig: (0, bip371_1.serializeTaprootSignature)(
796 sig,
797 input.sighashType,
798 ),
799 };
800 });
801 signaturePromises.push(tapKeySigPromise);
802 }
803 const tapScriptHashes = hashesForSig.filter(h => !!h.leafHash);
804 if (tapScriptHashes.length) {
805 const tapScriptSigPromises = tapScriptHashes.map(tsh => {
806 return Promise.resolve(keyPair.signSchnorr(tsh.hash)).then(
807 signature => {
808 const tapScriptSig = [
809 {
810 pubkey: (0, bip371_1.toXOnly)(keyPair.publicKey),
811 signature: (0, bip371_1.serializeTaprootSignature)(
812 signature,
813 input.sighashType,
814 ),
815 leafHash: tsh.leafHash,
816 },
817 ];
818 return { tapScriptSig };
819 },
820 );
821 });
822 signaturePromises.push(...tapScriptSigPromises);
823 }
824 return Promise.all(signaturePromises).then(results => {
825 results.forEach(v => this.data.updateInput(inputIndex, v));
826 });
827 }
828 checkTaprootHashesForSig(
829 inputIndex,
830 input,
831 keyPair,
832 tapLeafHashToSign,
833 allowedSighashTypes,
834 ) {
835 if (typeof keyPair.signSchnorr !== 'function')
836 throw new Error(
837 `Need Schnorr Signer to sign taproot input #${inputIndex}.`,
838 );
839 const hashesForSig = getTaprootHashesForSig(
840 inputIndex,
841 input,
842 this.data.inputs,
843 keyPair.publicKey,
844 this.__CACHE,
845 tapLeafHashToSign,
846 allowedSighashTypes,
847 );
848 if (!hashesForSig || !hashesForSig.length)
849 throw new Error(
850 `Can not sign for input #${inputIndex} with the key ${keyPair.publicKey.toString(
851 'hex',
852 )}`,
853 );
854 return hashesForSig;
855 }
856 toBuffer() {
857 checkCache(this.__CACHE);
858 return this.data.toBuffer();
859 }
860 toHex() {
861 checkCache(this.__CACHE);
862 return this.data.toHex();
863 }
864 toBase64() {
865 checkCache(this.__CACHE);
866 return this.data.toBase64();
867 }
868 updateGlobal(updateData) {
869 this.data.updateGlobal(updateData);
870 return this;
871 }
872 updateInput(inputIndex, updateData) {
873 if (updateData.witnessScript) checkInvalidP2WSH(updateData.witnessScript);
874 (0, bip371_1.checkTaprootInputFields)(
875 this.data.inputs[inputIndex],
876 updateData,
877 'updateInput',
878 );
879 this.data.updateInput(inputIndex, updateData);
880 if (updateData.nonWitnessUtxo) {
881 addNonWitnessTxCache(
882 this.__CACHE,
883 this.data.inputs[inputIndex],
884 inputIndex,
885 );
886 }
887 return this;
888 }
889 updateOutput(outputIndex, updateData) {
890 const outputData = this.data.outputs[outputIndex];
891 (0, bip371_1.checkTaprootOutputFields)(
892 outputData,
893 updateData,
894 'updateOutput',
895 );
896 this.data.updateOutput(outputIndex, updateData);
897 return this;
898 }
899 addUnknownKeyValToGlobal(keyVal) {
900 this.data.addUnknownKeyValToGlobal(keyVal);
901 return this;
902 }
903 addUnknownKeyValToInput(inputIndex, keyVal) {
904 this.data.addUnknownKeyValToInput(inputIndex, keyVal);
905 return this;
906 }
907 addUnknownKeyValToOutput(outputIndex, keyVal) {
908 this.data.addUnknownKeyValToOutput(outputIndex, keyVal);
909 return this;
910 }
911 clearFinalizedInput(inputIndex) {
912 this.data.clearFinalizedInput(inputIndex);
913 return this;
914 }
915}
916exports.Psbt = Psbt;
917/**
918 * This function is needed to pass to the bip174 base class's fromBuffer.
919 * It takes the "transaction buffer" portion of the psbt buffer and returns a
920 * Transaction (From the bip174 library) interface.
921 */
922const transactionFromBuffer = buffer => new PsbtTransaction(buffer);
923/**
924 * This class implements the Transaction interface from bip174 library.
925 * It contains a bitcoinjs-lib Transaction object.
926 */
927class PsbtTransaction {
928 constructor(buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) {
929 this.tx = transaction_1.Transaction.fromBuffer(buffer);
930 checkTxEmpty(this.tx);
931 Object.defineProperty(this, 'tx', {
932 enumerable: false,
933 writable: true,
934 });
935 }
936 getInputOutputCounts() {
937 return {
938 inputCount: this.tx.ins.length,
939 outputCount: this.tx.outs.length,
940 };
941 }
942 addInput(input) {
943 if (
944 input.hash === undefined ||
945 input.index === undefined ||
946 (!Buffer.isBuffer(input.hash) && typeof input.hash !== 'string') ||
947 typeof input.index !== 'number'
948 ) {
949 throw new Error('Error adding input.');
950 }
951 const hash =
952 typeof input.hash === 'string'
953 ? (0, bufferutils_1.reverseBuffer)(Buffer.from(input.hash, 'hex'))
954 : input.hash;
955 this.tx.addInput(hash, input.index, input.sequence);
956 }
957 addOutput(output) {
958 if (
959 output.script === undefined ||
960 output.value === undefined ||
961 !Buffer.isBuffer(output.script) ||
962 typeof output.value !== 'number'
963 ) {
964 throw new Error('Error adding output.');
965 }
966 this.tx.addOutput(output.script, output.value);
967 }
968 toBuffer() {
969 return this.tx.toBuffer();
970 }
971}
972function canFinalize(input, script, scriptType) {
973 switch (scriptType) {
974 case 'pubkey':
975 case 'pubkeyhash':
976 case 'witnesspubkeyhash':
977 return hasSigs(1, input.partialSig);
978 case 'multisig':
979 const p2ms = payments.p2ms({ output: script });
980 return hasSigs(p2ms.m, input.partialSig, p2ms.pubkeys);
981 default:
982 return false;
983 }
984}
985function checkCache(cache) {
986 if (cache.__UNSAFE_SIGN_NONSEGWIT !== false) {
987 throw new Error('Not BIP174 compliant, can not export');
988 }
989}
990function hasSigs(neededSigs, partialSig, pubkeys) {
991 if (!partialSig) return false;
992 let sigs;
993 if (pubkeys) {
994 sigs = pubkeys
995 .map(pkey => {
996 const pubkey = compressPubkey(pkey);
997 return partialSig.find(pSig => pSig.pubkey.equals(pubkey));
998 })
999 .filter(v => !!v);
1000 } else {
1001 sigs = partialSig;
1002 }
1003 if (sigs.length > neededSigs) throw new Error('Too many signatures');
1004 return sigs.length === neededSigs;
1005}
1006function isFinalized(input) {
1007 return !!input.finalScriptSig || !!input.finalScriptWitness;
1008}
1009function bip32DerivationIsMine(root) {
1010 return d => {
1011 if (!d.masterFingerprint.equals(root.fingerprint)) return false;
1012 if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false;
1013 return true;
1014 };
1015}
1016function check32Bit(num) {
1017 if (
1018 typeof num !== 'number' ||
1019 num !== Math.floor(num) ||
1020 num > 0xffffffff ||
1021 num < 0
1022 ) {
1023 throw new Error('Invalid 32 bit integer');
1024 }
1025}
1026function checkFees(psbt, cache, opts) {
1027 const feeRate = cache.__FEE_RATE || psbt.getFeeRate();
1028 const vsize = cache.__EXTRACTED_TX.virtualSize();
1029 const satoshis = feeRate * vsize;
1030 if (feeRate >= opts.maximumFeeRate) {
1031 throw new Error(
1032 `Warning: You are paying around ${(satoshis / 1e8).toFixed(8)} in ` +
1033 `fees, which is ${feeRate} satoshi per byte for a transaction ` +
1034 `with a VSize of ${vsize} bytes (segwit counted as 0.25 byte per ` +
1035 `byte). Use setMaximumFeeRate method to raise your threshold, or ` +
1036 `pass true to the first arg of extractTransaction.`,
1037 );
1038 }
1039}
1040function checkInputsForPartialSig(inputs, action) {
1041 inputs.forEach(input => {
1042 const throws = (0, bip371_1.isTaprootInput)(input)
1043 ? (0, bip371_1.checkTaprootInputForSigs)(input, action)
1044 : (0, psbtutils_1.checkInputForSig)(input, action);
1045 if (throws)
1046 throw new Error('Can not modify transaction, signatures exist.');
1047 });
1048}
1049function checkPartialSigSighashes(input) {
1050 if (!input.sighashType || !input.partialSig) return;
1051 const { partialSig, sighashType } = input;
1052 partialSig.forEach(pSig => {
1053 const { hashType } = bscript.signature.decode(pSig.signature);
1054 if (sighashType !== hashType) {
1055 throw new Error('Signature sighash does not match input sighash type');
1056 }
1057 });
1058}
1059function checkScriptForPubkey(pubkey, script, action) {
1060 if (!(0, psbtutils_1.pubkeyInScript)(pubkey, script)) {
1061 throw new Error(
1062 `Can not ${action} for this input with the key ${pubkey.toString('hex')}`,
1063 );
1064 }
1065}
1066function checkTxEmpty(tx) {
1067 const isEmpty = tx.ins.every(
1068 input =>
1069 input.script &&
1070 input.script.length === 0 &&
1071 input.witness &&
1072 input.witness.length === 0,
1073 );
1074 if (!isEmpty) {
1075 throw new Error('Format Error: Transaction ScriptSigs are not empty');
1076 }
1077}
1078function checkTxForDupeIns(tx, cache) {
1079 tx.ins.forEach(input => {
1080 checkTxInputCache(cache, input);
1081 });
1082}
1083function checkTxInputCache(cache, input) {
1084 const key =
1085 (0, bufferutils_1.reverseBuffer)(Buffer.from(input.hash)).toString('hex') +
1086 ':' +
1087 input.index;
1088 if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.');
1089 cache.__TX_IN_CACHE[key] = 1;
1090}
1091function scriptCheckerFactory(payment, paymentScriptName) {
1092 return (inputIndex, scriptPubKey, redeemScript, ioType) => {
1093 const redeemScriptOutput = payment({
1094 redeem: { output: redeemScript },
1095 }).output;
1096 if (!scriptPubKey.equals(redeemScriptOutput)) {
1097 throw new Error(
1098 `${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`,
1099 );
1100 }
1101 };
1102}
1103const checkRedeemScript = scriptCheckerFactory(payments.p2sh, 'Redeem script');
1104const checkWitnessScript = scriptCheckerFactory(
1105 payments.p2wsh,
1106 'Witness script',
1107);
1108function getTxCacheValue(key, name, inputs, c) {
1109 if (!inputs.every(isFinalized))
1110 throw new Error(`PSBT must be finalized to calculate ${name}`);
1111 if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE;
1112 if (key === '__FEE' && c.__FEE) return c.__FEE;
1113 let tx;
1114 let mustFinalize = true;
1115 if (c.__EXTRACTED_TX) {
1116 tx = c.__EXTRACTED_TX;
1117 mustFinalize = false;
1118 } else {
1119 tx = c.__TX.clone();
1120 }
1121 inputFinalizeGetAmts(inputs, tx, c, mustFinalize);
1122 if (key === '__FEE_RATE') return c.__FEE_RATE;
1123 else if (key === '__FEE') return c.__FEE;
1124}
1125function getFinalScripts(inputIndex, input, script, isSegwit, isP2SH, isP2WSH) {
1126 const scriptType = classifyScript(script);
1127 if (!canFinalize(input, script, scriptType))
1128 throw new Error(`Can not finalize input #${inputIndex}`);
1129 return prepareFinalScripts(
1130 script,
1131 scriptType,
1132 input.partialSig,
1133 isSegwit,
1134 isP2SH,
1135 isP2WSH,
1136 );
1137}
1138function prepareFinalScripts(
1139 script,
1140 scriptType,
1141 partialSig,
1142 isSegwit,
1143 isP2SH,
1144 isP2WSH,
1145) {
1146 let finalScriptSig;
1147 let finalScriptWitness;
1148 // Wow, the payments API is very handy
1149 const payment = getPayment(script, scriptType, partialSig);
1150 const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment });
1151 const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
1152 if (isSegwit) {
1153 if (p2wsh) {
1154 finalScriptWitness = (0, psbtutils_1.witnessStackToScriptWitness)(
1155 p2wsh.witness,
1156 );
1157 } else {
1158 finalScriptWitness = (0, psbtutils_1.witnessStackToScriptWitness)(
1159 payment.witness,
1160 );
1161 }
1162 if (p2sh) {
1163 finalScriptSig = p2sh.input;
1164 }
1165 } else {
1166 if (p2sh) {
1167 finalScriptSig = p2sh.input;
1168 } else {
1169 finalScriptSig = payment.input;
1170 }
1171 }
1172 return {
1173 finalScriptSig,
1174 finalScriptWitness,
1175 };
1176}
1177function getHashAndSighashType(
1178 inputs,
1179 inputIndex,
1180 pubkey,
1181 cache,
1182 sighashTypes,
1183) {
1184 const input = (0, utils_1.checkForInput)(inputs, inputIndex);
1185 const { hash, sighashType, script } = getHashForSig(
1186 inputIndex,
1187 input,
1188 cache,
1189 false,
1190 sighashTypes,
1191 );
1192 checkScriptForPubkey(pubkey, script, 'sign');
1193 return {
1194 hash,
1195 sighashType,
1196 };
1197}
1198function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
1199 const unsignedTx = cache.__TX;
1200 const sighashType =
1201 input.sighashType || transaction_1.Transaction.SIGHASH_ALL;
1202 checkSighashTypeAllowed(sighashType, sighashTypes);
1203 let hash;
1204 let prevout;
1205 if (input.nonWitnessUtxo) {
1206 const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
1207 cache,
1208 input,
1209 inputIndex,
1210 );
1211 const prevoutHash = unsignedTx.ins[inputIndex].hash;
1212 const utxoHash = nonWitnessUtxoTx.getHash();
1213 // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout
1214 if (!prevoutHash.equals(utxoHash)) {
1215 throw new Error(
1216 `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`,
1217 );
1218 }
1219 const prevoutIndex = unsignedTx.ins[inputIndex].index;
1220 prevout = nonWitnessUtxoTx.outs[prevoutIndex];
1221 } else if (input.witnessUtxo) {
1222 prevout = input.witnessUtxo;
1223 } else {
1224 throw new Error('Need a Utxo input item for signing');
1225 }
1226 const { meaningfulScript, type } = getMeaningfulScript(
1227 prevout.script,
1228 inputIndex,
1229 'input',
1230 input.redeemScript,
1231 input.witnessScript,
1232 );
1233 if (['p2sh-p2wsh', 'p2wsh'].indexOf(type) >= 0) {
1234 hash = unsignedTx.hashForWitnessV0(
1235 inputIndex,
1236 meaningfulScript,
1237 prevout.value,
1238 sighashType,
1239 );
1240 } else if ((0, psbtutils_1.isP2WPKH)(meaningfulScript)) {
1241 // P2WPKH uses the P2PKH template for prevoutScript when signing
1242 const signingScript = payments.p2pkh({
1243 hash: meaningfulScript.slice(2),
1244 }).output;
1245 hash = unsignedTx.hashForWitnessV0(
1246 inputIndex,
1247 signingScript,
1248 prevout.value,
1249 sighashType,
1250 );
1251 } else {
1252 // non-segwit
1253 if (
1254 input.nonWitnessUtxo === undefined &&
1255 cache.__UNSAFE_SIGN_NONSEGWIT === false
1256 )
1257 throw new Error(
1258 `Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
1259 `${meaningfulScript.toString('hex')}`,
1260 );
1261 if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT !== false)
1262 console.warn(
1263 'Warning: Signing non-segwit inputs without the full parent transaction ' +
1264 'means there is a chance that a miner could feed you incorrect information ' +
1265 "to trick you into paying large fees. This behavior is the same as Psbt's predecesor " +
1266 '(TransactionBuilder - now removed) when signing non-segwit scripts. You are not ' +
1267 'able to export this Psbt with toBuffer|toBase64|toHex since it is not ' +
1268 'BIP174 compliant.\n*********************\nPROCEED WITH CAUTION!\n' +
1269 '*********************',
1270 );
1271 hash = unsignedTx.hashForSignature(
1272 inputIndex,
1273 meaningfulScript,
1274 sighashType,
1275 );
1276 }
1277 return {
1278 script: meaningfulScript,
1279 sighashType,
1280 hash,
1281 };
1282}
1283function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
1284 const allPublicKeys = [];
1285 if (input.tapInternalKey) {
1286 const key = getPrevoutTaprootKey(inputIndex, input, cache);
1287 if (key) {
1288 allPublicKeys.push(key);
1289 }
1290 }
1291 if (input.tapScriptSig) {
1292 const tapScriptPubkeys = input.tapScriptSig.map(tss => tss.pubkey);
1293 allPublicKeys.push(...tapScriptPubkeys);
1294 }
1295 const allHashes = allPublicKeys.map(pubicKey =>
1296 getTaprootHashesForSig(inputIndex, input, inputs, pubicKey, cache),
1297 );
1298 return allHashes.flat();
1299}
1300function getPrevoutTaprootKey(inputIndex, input, cache) {
1301 const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache);
1302 return (0, psbtutils_1.isP2TR)(script) ? script.subarray(2, 34) : null;
1303}
1304function trimTaprootSig(signature) {
1305 return signature.length === 64 ? signature : signature.subarray(0, 64);
1306}
1307function getTaprootHashesForSig(
1308 inputIndex,
1309 input,
1310 inputs,
1311 pubkey,
1312 cache,
1313 tapLeafHashToSign,
1314 allowedSighashTypes,
1315) {
1316 const unsignedTx = cache.__TX;
1317 const sighashType =
1318 input.sighashType || transaction_1.Transaction.SIGHASH_DEFAULT;
1319 checkSighashTypeAllowed(sighashType, allowedSighashTypes);
1320 const prevOuts = inputs.map((i, index) =>
1321 getScriptAndAmountFromUtxo(index, i, cache),
1322 );
1323 const signingScripts = prevOuts.map(o => o.script);
1324 const values = prevOuts.map(o => o.value);
1325 const hashes = [];
1326 if (input.tapInternalKey && !tapLeafHashToSign) {
1327 const outputKey =
1328 getPrevoutTaprootKey(inputIndex, input, cache) || Buffer.from([]);
1329 if ((0, bip371_1.toXOnly)(pubkey).equals(outputKey)) {
1330 const tapKeyHash = unsignedTx.hashForWitnessV1(
1331 inputIndex,
1332 signingScripts,
1333 values,
1334 sighashType,
1335 );
1336 hashes.push({ pubkey, hash: tapKeyHash });
1337 }
1338 }
1339 const tapLeafHashes = (input.tapLeafScript || [])
1340 .filter(tapLeaf => (0, psbtutils_1.pubkeyInScript)(pubkey, tapLeaf.script))
1341 .map(tapLeaf => {
1342 const hash = (0, bip341_1.tapleafHash)({
1343 output: tapLeaf.script,
1344 version: tapLeaf.leafVersion,
1345 });
1346 return Object.assign({ hash }, tapLeaf);
1347 })
1348 .filter(
1349 tapLeaf => !tapLeafHashToSign || tapLeafHashToSign.equals(tapLeaf.hash),
1350 )
1351 .map(tapLeaf => {
1352 const tapScriptHash = unsignedTx.hashForWitnessV1(
1353 inputIndex,
1354 signingScripts,
1355 values,
1356 transaction_1.Transaction.SIGHASH_DEFAULT,
1357 tapLeaf.hash,
1358 );
1359 return {
1360 pubkey,
1361 hash: tapScriptHash,
1362 leafHash: tapLeaf.hash,
1363 };
1364 });
1365 return hashes.concat(tapLeafHashes);
1366}
1367function checkSighashTypeAllowed(sighashType, sighashTypes) {
1368 if (sighashTypes && sighashTypes.indexOf(sighashType) < 0) {
1369 const str = sighashTypeToString(sighashType);
1370 throw new Error(
1371 `Sighash type is not allowed. Retry the sign method passing the ` +
1372 `sighashTypes array of whitelisted types. Sighash type: ${str}`,
1373 );
1374 }
1375}
1376function getPayment(script, scriptType, partialSig) {
1377 let payment;
1378 switch (scriptType) {
1379 case 'multisig':
1380 const sigs = getSortedSigs(script, partialSig);
1381 payment = payments.p2ms({
1382 output: script,
1383 signatures: sigs,
1384 });
1385 break;
1386 case 'pubkey':
1387 payment = payments.p2pk({
1388 output: script,
1389 signature: partialSig[0].signature,
1390 });
1391 break;
1392 case 'pubkeyhash':
1393 payment = payments.p2pkh({
1394 output: script,
1395 pubkey: partialSig[0].pubkey,
1396 signature: partialSig[0].signature,
1397 });
1398 break;
1399 case 'witnesspubkeyhash':
1400 payment = payments.p2wpkh({
1401 output: script,
1402 pubkey: partialSig[0].pubkey,
1403 signature: partialSig[0].signature,
1404 });
1405 break;
1406 }
1407 return payment;
1408}
1409function getScriptFromInput(inputIndex, input, cache) {
1410 const unsignedTx = cache.__TX;
1411 const res = {
1412 script: null,
1413 isSegwit: false,
1414 isP2SH: false,
1415 isP2WSH: false,
1416 };
1417 res.isP2SH = !!input.redeemScript;
1418 res.isP2WSH = !!input.witnessScript;
1419 if (input.witnessScript) {
1420 res.script = input.witnessScript;
1421 } else if (input.redeemScript) {
1422 res.script = input.redeemScript;
1423 } else {
1424 if (input.nonWitnessUtxo) {
1425 const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
1426 cache,
1427 input,
1428 inputIndex,
1429 );
1430 const prevoutIndex = unsignedTx.ins[inputIndex].index;
1431 res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;
1432 } else if (input.witnessUtxo) {
1433 res.script = input.witnessUtxo.script;
1434 }
1435 }
1436 if (input.witnessScript || (0, psbtutils_1.isP2WPKH)(res.script)) {
1437 res.isSegwit = true;
1438 }
1439 return res;
1440}
1441function getSignersFromHD(inputIndex, inputs, hdKeyPair) {
1442 const input = (0, utils_1.checkForInput)(inputs, inputIndex);
1443 if (!input.bip32Derivation || input.bip32Derivation.length === 0) {
1444 throw new Error('Need bip32Derivation to sign with HD');
1445 }
1446 const myDerivations = input.bip32Derivation
1447 .map(bipDv => {
1448 if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) {
1449 return bipDv;
1450 } else {
1451 return;
1452 }
1453 })
1454 .filter(v => !!v);
1455 if (myDerivations.length === 0) {
1456 throw new Error(
1457 'Need one bip32Derivation masterFingerprint to match the HDSigner fingerprint',
1458 );
1459 }
1460 const signers = myDerivations.map(bipDv => {
1461 const node = hdKeyPair.derivePath(bipDv.path);
1462 if (!bipDv.pubkey.equals(node.publicKey)) {
1463 throw new Error('pubkey did not match bip32Derivation');
1464 }
1465 return node;
1466 });
1467 return signers;
1468}
1469function getSortedSigs(script, partialSig) {
1470 const p2ms = payments.p2ms({ output: script });
1471 // for each pubkey in order of p2ms script
1472 return p2ms.pubkeys
1473 .map(pk => {
1474 // filter partialSig array by pubkey being equal
1475 return (
1476 partialSig.filter(ps => {
1477 return ps.pubkey.equals(pk);
1478 })[0] || {}
1479 ).signature;
1480 // Any pubkey without a match will return undefined
1481 // this last filter removes all the undefined items in the array.
1482 })
1483 .filter(v => !!v);
1484}
1485function scriptWitnessToWitnessStack(buffer) {
1486 let offset = 0;
1487 function readSlice(n) {
1488 offset += n;
1489 return buffer.slice(offset - n, offset);
1490 }
1491 function readVarInt() {
1492 const vi = varuint.decode(buffer, offset);
1493 offset += varuint.decode.bytes;
1494 return vi;
1495 }
1496 function readVarSlice() {
1497 return readSlice(readVarInt());
1498 }
1499 function readVector() {
1500 const count = readVarInt();
1501 const vector = [];
1502 for (let i = 0; i < count; i++) vector.push(readVarSlice());
1503 return vector;
1504 }
1505 return readVector();
1506}
1507function sighashTypeToString(sighashType) {
1508 let text =
1509 sighashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY
1510 ? 'SIGHASH_ANYONECANPAY | '
1511 : '';
1512 const sigMod = sighashType & 0x1f;
1513 switch (sigMod) {
1514 case transaction_1.Transaction.SIGHASH_ALL:
1515 text += 'SIGHASH_ALL';
1516 break;
1517 case transaction_1.Transaction.SIGHASH_SINGLE:
1518 text += 'SIGHASH_SINGLE';
1519 break;
1520 case transaction_1.Transaction.SIGHASH_NONE:
1521 text += 'SIGHASH_NONE';
1522 break;
1523 }
1524 return text;
1525}
1526function addNonWitnessTxCache(cache, input, inputIndex) {
1527 cache.__NON_WITNESS_UTXO_BUF_CACHE[inputIndex] = input.nonWitnessUtxo;
1528 const tx = transaction_1.Transaction.fromBuffer(input.nonWitnessUtxo);
1529 cache.__NON_WITNESS_UTXO_TX_CACHE[inputIndex] = tx;
1530 const self = cache;
1531 const selfIndex = inputIndex;
1532 delete input.nonWitnessUtxo;
1533 Object.defineProperty(input, 'nonWitnessUtxo', {
1534 enumerable: true,
1535 get() {
1536 const buf = self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex];
1537 const txCache = self.__NON_WITNESS_UTXO_TX_CACHE[selfIndex];
1538 if (buf !== undefined) {
1539 return buf;
1540 } else {
1541 const newBuf = txCache.toBuffer();
1542 self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = newBuf;
1543 return newBuf;
1544 }
1545 },
1546 set(data) {
1547 self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = data;
1548 },
1549 });
1550}
1551function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) {
1552 let inputAmount = 0;
1553 inputs.forEach((input, idx) => {
1554 if (mustFinalize && input.finalScriptSig)
1555 tx.ins[idx].script = input.finalScriptSig;
1556 if (mustFinalize && input.finalScriptWitness) {
1557 tx.ins[idx].witness = scriptWitnessToWitnessStack(
1558 input.finalScriptWitness,
1559 );
1560 }
1561 if (input.witnessUtxo) {
1562 inputAmount += input.witnessUtxo.value;
1563 } else if (input.nonWitnessUtxo) {
1564 const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx);
1565 const vout = tx.ins[idx].index;
1566 const out = nwTx.outs[vout];
1567 inputAmount += out.value;
1568 }
1569 });
1570 const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0);
1571 const fee = inputAmount - outputAmount;
1572 if (fee < 0) {
1573 throw new Error('Outputs are spending more than Inputs');
1574 }
1575 const bytes = tx.virtualSize();
1576 cache.__FEE = fee;
1577 cache.__EXTRACTED_TX = tx;
1578 cache.__FEE_RATE = Math.floor(fee / bytes);
1579}
1580function nonWitnessUtxoTxFromCache(cache, input, inputIndex) {
1581 const c = cache.__NON_WITNESS_UTXO_TX_CACHE;
1582 if (!c[inputIndex]) {
1583 addNonWitnessTxCache(cache, input, inputIndex);
1584 }
1585 return c[inputIndex];
1586}
1587function getScriptFromUtxo(inputIndex, input, cache) {
1588 const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache);
1589 return script;
1590}
1591function getScriptAndAmountFromUtxo(inputIndex, input, cache) {
1592 if (input.witnessUtxo !== undefined) {
1593 return {
1594 script: input.witnessUtxo.script,
1595 value: input.witnessUtxo.value,
1596 };
1597 } else if (input.nonWitnessUtxo !== undefined) {
1598 const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
1599 cache,
1600 input,
1601 inputIndex,
1602 );
1603 const o = nonWitnessUtxoTx.outs[cache.__TX.ins[inputIndex].index];
1604 return { script: o.script, value: o.value };
1605 } else {
1606 throw new Error("Can't find pubkey in input without Utxo data");
1607 }
1608}
1609function pubkeyInInput(pubkey, input, inputIndex, cache) {
1610 const script = getScriptFromUtxo(inputIndex, input, cache);
1611 const { meaningfulScript } = getMeaningfulScript(
1612 script,
1613 inputIndex,
1614 'input',
1615 input.redeemScript,
1616 input.witnessScript,
1617 );
1618 return (0, psbtutils_1.pubkeyInScript)(pubkey, meaningfulScript);
1619}
1620function pubkeyInOutput(pubkey, output, outputIndex, cache) {
1621 const script = cache.__TX.outs[outputIndex].script;
1622 const { meaningfulScript } = getMeaningfulScript(
1623 script,
1624 outputIndex,
1625 'output',
1626 output.redeemScript,
1627 output.witnessScript,
1628 );
1629 return (0, psbtutils_1.pubkeyInScript)(pubkey, meaningfulScript);
1630}
1631function redeemFromFinalScriptSig(finalScript) {
1632 if (!finalScript) return;
1633 const decomp = bscript.decompile(finalScript);
1634 if (!decomp) return;
1635 const lastItem = decomp[decomp.length - 1];
1636 if (
1637 !Buffer.isBuffer(lastItem) ||
1638 isPubkeyLike(lastItem) ||
1639 isSigLike(lastItem)
1640 )
1641 return;
1642 const sDecomp = bscript.decompile(lastItem);
1643 if (!sDecomp) return;
1644 return lastItem;
1645}
1646function redeemFromFinalWitnessScript(finalScript) {
1647 if (!finalScript) return;
1648 const decomp = scriptWitnessToWitnessStack(finalScript);
1649 const lastItem = decomp[decomp.length - 1];
1650 if (isPubkeyLike(lastItem)) return;
1651 const sDecomp = bscript.decompile(lastItem);
1652 if (!sDecomp) return;
1653 return lastItem;
1654}
1655function compressPubkey(pubkey) {
1656 if (pubkey.length === 65) {
1657 const parity = pubkey[64] & 1;
1658 const newKey = pubkey.slice(0, 33);
1659 newKey[0] = 2 | parity;
1660 return newKey;
1661 }
1662 return pubkey.slice();
1663}
1664function isPubkeyLike(buf) {
1665 return buf.length === 33 && bscript.isCanonicalPubKey(buf);
1666}
1667function isSigLike(buf) {
1668 return bscript.isCanonicalScriptSignature(buf);
1669}
1670function getMeaningfulScript(
1671 script,
1672 index,
1673 ioType,
1674 redeemScript,
1675 witnessScript,
1676) {
1677 const isP2SH = (0, psbtutils_1.isP2SHScript)(script);
1678 const isP2SHP2WSH =
1679 isP2SH && redeemScript && (0, psbtutils_1.isP2WSHScript)(redeemScript);
1680 const isP2WSH = (0, psbtutils_1.isP2WSHScript)(script);
1681 if (isP2SH && redeemScript === undefined)
1682 throw new Error('scriptPubkey is P2SH but redeemScript missing');
1683 if ((isP2WSH || isP2SHP2WSH) && witnessScript === undefined)
1684 throw new Error(
1685 'scriptPubkey or redeemScript is P2WSH but witnessScript missing',
1686 );
1687 let meaningfulScript;
1688 if (isP2SHP2WSH) {
1689 meaningfulScript = witnessScript;
1690 checkRedeemScript(index, script, redeemScript, ioType);
1691 checkWitnessScript(index, redeemScript, witnessScript, ioType);
1692 checkInvalidP2WSH(meaningfulScript);
1693 } else if (isP2WSH) {
1694 meaningfulScript = witnessScript;
1695 checkWitnessScript(index, script, witnessScript, ioType);
1696 checkInvalidP2WSH(meaningfulScript);
1697 } else if (isP2SH) {
1698 meaningfulScript = redeemScript;
1699 checkRedeemScript(index, script, redeemScript, ioType);
1700 } else {
1701 meaningfulScript = script;
1702 }
1703 return {
1704 meaningfulScript,
1705 type: isP2SHP2WSH
1706 ? 'p2sh-p2wsh'
1707 : isP2SH
1708 ? 'p2sh'
1709 : isP2WSH
1710 ? 'p2wsh'
1711 : 'raw',
1712 };
1713}
1714function checkInvalidP2WSH(script) {
1715 if (
1716 (0, psbtutils_1.isP2WPKH)(script) ||
1717 (0, psbtutils_1.isP2SHScript)(script)
1718 ) {
1719 throw new Error('P2WPKH or P2SH can not be contained within P2WSH');
1720 }
1721}
1722function classifyScript(script) {
1723 if ((0, psbtutils_1.isP2WPKH)(script)) return 'witnesspubkeyhash';
1724 if ((0, psbtutils_1.isP2PKH)(script)) return 'pubkeyhash';
1725 if ((0, psbtutils_1.isP2MS)(script)) return 'multisig';
1726 if ((0, psbtutils_1.isP2PK)(script)) return 'pubkey';
1727 return 'nonstandard';
1728}
1729function range(n) {
1730 return [...Array(n).keys()];
1731}