UNPKG

37.2 kBJavaScriptView Raw
1'use strict';
2Object.defineProperty(exports, '__esModule', { value: true });
3const bip174_1 = require('bip174');
4const varuint = require('bip174/src/lib/converter/varint');
5const utils_1 = require('bip174/src/lib/utils');
6const address_1 = require('./address');
7const bufferutils_1 = require('./bufferutils');
8const crypto_1 = require('./crypto');
9const ecpair_1 = require('./ecpair');
10const networks_1 = require('./networks');
11const payments = require('./payments');
12const bscript = require('./script');
13const transaction_1 = require('./transaction');
14/**
15 * These are the default arguments for a Psbt instance.
16 */
17const DEFAULT_OPTS = {
18 /**
19 * A bitcoinjs Network object. This is only used if you pass an `address`
20 * parameter to addOutput. Otherwise it is not needed and can be left default.
21 */
22 network: networks_1.bitcoin,
23 /**
24 * When extractTransaction is called, the fee rate is checked.
25 * THIS IS NOT TO BE RELIED ON.
26 * It is only here as a last ditch effort to prevent sending a 500 BTC fee etc.
27 */
28 maximumFeeRate: 5000,
29};
30/**
31 * Psbt class can parse and generate a PSBT binary based off of the BIP174.
32 * There are 6 roles that this class fulfills. (Explained in BIP174)
33 *
34 * Creator: This can be done with `new Psbt()`
35 * Updater: This can be done with `psbt.addInput(input)`, `psbt.addInputs(inputs)`,
36 * `psbt.addOutput(output)`, `psbt.addOutputs(outputs)` when you are looking to
37 * add new inputs and outputs to the PSBT, and `psbt.updateGlobal(itemObject)`,
38 * `psbt.updateInput(itemObject)`, `psbt.updateOutput(itemObject)`
39 * addInput requires hash: Buffer | string; and index: number; as attributes
40 * and can also include any attributes that are used in updateInput method.
41 * addOutput requires script: Buffer; and value: number; and likewise can include
42 * data for updateOutput.
43 * For a list of what attributes should be what types. Check the bip174 library.
44 * Also, check the integration tests for some examples of usage.
45 * Signer: There are a few methods. signAllInputs and signAllInputsAsync, which will search all input
46 * information for your pubkey or pubkeyhash, and only sign inputs where it finds
47 * your info. Or you can explicitly sign a specific input with signInput and
48 * signInputAsync. For the async methods you can create a SignerAsync object
49 * and use something like a hardware wallet to sign with. (You must implement this)
50 * Combiner: psbts can be combined easily with `psbt.combine(psbt2, psbt3, psbt4 ...)`
51 * the psbt calling combine will always have precedence when a conflict occurs.
52 * Combine checks if the internal bitcoin transaction is the same, so be sure that
53 * all sequences, version, locktime, etc. are the same before combining.
54 * Input Finalizer: This role is fairly important. Not only does it need to construct
55 * the input scriptSigs and witnesses, but it SHOULD verify the signatures etc.
56 * Before running `psbt.finalizeAllInputs()` please run `psbt.validateSignaturesOfAllInputs()`
57 * Running any finalize method will delete any data in the input(s) that are no longer
58 * needed due to the finalized scripts containing the information.
59 * Transaction Extractor: This role will perform some checks before returning a
60 * Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
61 */
62class Psbt {
63 constructor(opts = {}, data = new bip174_1.Psbt(new PsbtTransaction())) {
64 this.data = data;
65 // set defaults
66 this.opts = Object.assign({}, DEFAULT_OPTS, opts);
67 this.__CACHE = {
68 __NON_WITNESS_UTXO_TX_CACHE: [],
69 __NON_WITNESS_UTXO_BUF_CACHE: [],
70 __TX_IN_CACHE: {},
71 __TX: this.data.globalMap.unsignedTx.tx,
72 };
73 if (this.data.inputs.length === 0) this.setVersion(2);
74 // Make data hidden when enumerating
75 const dpew = (obj, attr, enumerable, writable) =>
76 Object.defineProperty(obj, attr, {
77 enumerable,
78 writable,
79 });
80 dpew(this, '__CACHE', false, true);
81 dpew(this, 'opts', false, true);
82 }
83 static fromBase64(data, opts = {}) {
84 const buffer = Buffer.from(data, 'base64');
85 return this.fromBuffer(buffer, opts);
86 }
87 static fromHex(data, opts = {}) {
88 const buffer = Buffer.from(data, 'hex');
89 return this.fromBuffer(buffer, opts);
90 }
91 static fromBuffer(buffer, opts = {}) {
92 const psbtBase = bip174_1.Psbt.fromBuffer(buffer, transactionFromBuffer);
93 const psbt = new Psbt(opts, psbtBase);
94 checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
95 return psbt;
96 }
97 get inputCount() {
98 return this.data.inputs.length;
99 }
100 combine(...those) {
101 this.data.combine(...those.map(o => o.data));
102 return this;
103 }
104 clone() {
105 // TODO: more efficient cloning
106 const res = Psbt.fromBuffer(this.data.toBuffer());
107 res.opts = JSON.parse(JSON.stringify(this.opts));
108 return res;
109 }
110 setMaximumFeeRate(satoshiPerByte) {
111 check32Bit(satoshiPerByte); // 42.9 BTC per byte IS excessive... so throw
112 this.opts.maximumFeeRate = satoshiPerByte;
113 }
114 setVersion(version) {
115 check32Bit(version);
116 checkInputsForPartialSig(this.data.inputs, 'setVersion');
117 const c = this.__CACHE;
118 c.__TX.version = version;
119 c.__EXTRACTED_TX = undefined;
120 return this;
121 }
122 setLocktime(locktime) {
123 check32Bit(locktime);
124 checkInputsForPartialSig(this.data.inputs, 'setLocktime');
125 const c = this.__CACHE;
126 c.__TX.locktime = locktime;
127 c.__EXTRACTED_TX = undefined;
128 return this;
129 }
130 setInputSequence(inputIndex, sequence) {
131 check32Bit(sequence);
132 checkInputsForPartialSig(this.data.inputs, 'setInputSequence');
133 const c = this.__CACHE;
134 if (c.__TX.ins.length <= inputIndex) {
135 throw new Error('Input index too high');
136 }
137 c.__TX.ins[inputIndex].sequence = sequence;
138 c.__EXTRACTED_TX = undefined;
139 return this;
140 }
141 addInputs(inputDatas) {
142 inputDatas.forEach(inputData => this.addInput(inputData));
143 return this;
144 }
145 addInput(inputData) {
146 checkInputsForPartialSig(this.data.inputs, 'addInput');
147 const c = this.__CACHE;
148 this.data.addInput(inputData);
149 const txIn = c.__TX.ins[c.__TX.ins.length - 1];
150 checkTxInputCache(c, txIn);
151 const inputIndex = this.data.inputs.length - 1;
152 const input = this.data.inputs[inputIndex];
153 if (input.nonWitnessUtxo) {
154 addNonWitnessTxCache(this.__CACHE, input, inputIndex);
155 }
156 c.__FEE = undefined;
157 c.__FEE_RATE = undefined;
158 c.__EXTRACTED_TX = undefined;
159 return this;
160 }
161 addOutputs(outputDatas) {
162 outputDatas.forEach(outputData => this.addOutput(outputData));
163 return this;
164 }
165 addOutput(outputData) {
166 checkInputsForPartialSig(this.data.inputs, 'addOutput');
167 const { address } = outputData;
168 if (typeof address === 'string') {
169 const { network } = this.opts;
170 const script = address_1.toOutputScript(address, network);
171 outputData = Object.assign(outputData, { script });
172 }
173 const c = this.__CACHE;
174 this.data.addOutput(outputData);
175 c.__FEE = undefined;
176 c.__FEE_RATE = undefined;
177 c.__EXTRACTED_TX = undefined;
178 return this;
179 }
180 extractTransaction(disableFeeCheck) {
181 if (!this.data.inputs.every(isFinalized)) throw new Error('Not finalized');
182 const c = this.__CACHE;
183 if (!disableFeeCheck) {
184 checkFees(this, c, this.opts);
185 }
186 if (c.__EXTRACTED_TX) return c.__EXTRACTED_TX;
187 const tx = c.__TX.clone();
188 inputFinalizeGetAmts(this.data.inputs, tx, c, true);
189 return tx;
190 }
191 getFeeRate() {
192 return getTxCacheValue(
193 '__FEE_RATE',
194 'fee rate',
195 this.data.inputs,
196 this.__CACHE,
197 );
198 }
199 getFee() {
200 return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE);
201 }
202 finalizeAllInputs() {
203 utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
204 range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx));
205 return this;
206 }
207 finalizeInput(inputIndex) {
208 const input = utils_1.checkForInput(this.data.inputs, inputIndex);
209 const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
210 inputIndex,
211 input,
212 this.__CACHE,
213 );
214 if (!script) throw new Error(`No script found for input #${inputIndex}`);
215 const scriptType = classifyScript(script);
216 if (!canFinalize(input, script, scriptType))
217 throw new Error(`Can not finalize input #${inputIndex}`);
218 checkPartialSigSighashes(input);
219 const { finalScriptSig, finalScriptWitness } = getFinalScripts(
220 script,
221 scriptType,
222 input.partialSig,
223 isSegwit,
224 isP2SH,
225 isP2WSH,
226 );
227 if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
228 if (finalScriptWitness)
229 this.data.updateInput(inputIndex, { finalScriptWitness });
230 if (!finalScriptSig && !finalScriptWitness)
231 throw new Error(`Unknown error finalizing input #${inputIndex}`);
232 this.data.clearFinalizedInput(inputIndex);
233 return this;
234 }
235 validateSignaturesOfAllInputs() {
236 utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
237 const results = range(this.data.inputs.length).map(idx =>
238 this.validateSignaturesOfInput(idx),
239 );
240 return results.reduce((final, res) => res === true && final, true);
241 }
242 validateSignaturesOfInput(inputIndex, pubkey) {
243 const input = this.data.inputs[inputIndex];
244 const partialSig = (input || {}).partialSig;
245 if (!input || !partialSig || partialSig.length < 1)
246 throw new Error('No signatures to validate');
247 const mySigs = pubkey
248 ? partialSig.filter(sig => sig.pubkey.equals(pubkey))
249 : partialSig;
250 if (mySigs.length < 1) throw new Error('No signatures for this pubkey');
251 const results = [];
252 let hashCache;
253 let scriptCache;
254 let sighashCache;
255 for (const pSig of mySigs) {
256 const sig = bscript.signature.decode(pSig.signature);
257 const { hash, script } =
258 sighashCache !== sig.hashType
259 ? getHashForSig(
260 inputIndex,
261 Object.assign({}, input, { sighashType: sig.hashType }),
262 this.__CACHE,
263 )
264 : { hash: hashCache, script: scriptCache };
265 sighashCache = sig.hashType;
266 hashCache = hash;
267 scriptCache = script;
268 checkScriptForPubkey(pSig.pubkey, script, 'verify');
269 const keypair = ecpair_1.fromPublicKey(pSig.pubkey);
270 results.push(keypair.verify(hash, sig.signature));
271 }
272 return results.every(res => res === true);
273 }
274 signAllInputsHD(
275 hdKeyPair,
276 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
277 ) {
278 if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
279 throw new Error('Need HDSigner to sign input');
280 }
281 const results = [];
282 for (const i of range(this.data.inputs.length)) {
283 try {
284 this.signInputHD(i, hdKeyPair, sighashTypes);
285 results.push(true);
286 } catch (err) {
287 results.push(false);
288 }
289 }
290 if (results.every(v => v === false)) {
291 throw new Error('No inputs were signed');
292 }
293 return this;
294 }
295 signAllInputsHDAsync(
296 hdKeyPair,
297 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
298 ) {
299 return new Promise((resolve, reject) => {
300 if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
301 return reject(new Error('Need HDSigner to sign input'));
302 }
303 const results = [];
304 const promises = [];
305 for (const i of range(this.data.inputs.length)) {
306 promises.push(
307 this.signInputHDAsync(i, hdKeyPair, sighashTypes).then(
308 () => {
309 results.push(true);
310 },
311 () => {
312 results.push(false);
313 },
314 ),
315 );
316 }
317 return Promise.all(promises).then(() => {
318 if (results.every(v => v === false)) {
319 return reject(new Error('No inputs were signed'));
320 }
321 resolve();
322 });
323 });
324 }
325 signInputHD(
326 inputIndex,
327 hdKeyPair,
328 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
329 ) {
330 if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
331 throw new Error('Need HDSigner to sign input');
332 }
333 const signers = getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair);
334 signers.forEach(signer => this.signInput(inputIndex, signer, sighashTypes));
335 return this;
336 }
337 signInputHDAsync(
338 inputIndex,
339 hdKeyPair,
340 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
341 ) {
342 return new Promise((resolve, reject) => {
343 if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
344 return reject(new Error('Need HDSigner to sign input'));
345 }
346 const signers = getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair);
347 const promises = signers.map(signer =>
348 this.signInputAsync(inputIndex, signer, sighashTypes),
349 );
350 return Promise.all(promises)
351 .then(() => {
352 resolve();
353 })
354 .catch(reject);
355 });
356 }
357 signAllInputs(
358 keyPair,
359 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
360 ) {
361 if (!keyPair || !keyPair.publicKey)
362 throw new Error('Need Signer to sign input');
363 // TODO: Add a pubkey/pubkeyhash cache to each input
364 // as input information is added, then eventually
365 // optimize this method.
366 const results = [];
367 for (const i of range(this.data.inputs.length)) {
368 try {
369 this.signInput(i, keyPair, sighashTypes);
370 results.push(true);
371 } catch (err) {
372 results.push(false);
373 }
374 }
375 if (results.every(v => v === false)) {
376 throw new Error('No inputs were signed');
377 }
378 return this;
379 }
380 signAllInputsAsync(
381 keyPair,
382 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
383 ) {
384 return new Promise((resolve, reject) => {
385 if (!keyPair || !keyPair.publicKey)
386 return reject(new Error('Need Signer to sign input'));
387 // TODO: Add a pubkey/pubkeyhash cache to each input
388 // as input information is added, then eventually
389 // optimize this method.
390 const results = [];
391 const promises = [];
392 for (const [i] of this.data.inputs.entries()) {
393 promises.push(
394 this.signInputAsync(i, keyPair, sighashTypes).then(
395 () => {
396 results.push(true);
397 },
398 () => {
399 results.push(false);
400 },
401 ),
402 );
403 }
404 return Promise.all(promises).then(() => {
405 if (results.every(v => v === false)) {
406 return reject(new Error('No inputs were signed'));
407 }
408 resolve();
409 });
410 });
411 }
412 signInput(
413 inputIndex,
414 keyPair,
415 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
416 ) {
417 if (!keyPair || !keyPair.publicKey)
418 throw new Error('Need Signer to sign input');
419 const { hash, sighashType } = getHashAndSighashType(
420 this.data.inputs,
421 inputIndex,
422 keyPair.publicKey,
423 this.__CACHE,
424 sighashTypes,
425 );
426 const partialSig = [
427 {
428 pubkey: keyPair.publicKey,
429 signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
430 },
431 ];
432 this.data.updateInput(inputIndex, { partialSig });
433 return this;
434 }
435 signInputAsync(
436 inputIndex,
437 keyPair,
438 sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
439 ) {
440 return new Promise((resolve, reject) => {
441 if (!keyPair || !keyPair.publicKey)
442 return reject(new Error('Need Signer to sign input'));
443 const { hash, sighashType } = getHashAndSighashType(
444 this.data.inputs,
445 inputIndex,
446 keyPair.publicKey,
447 this.__CACHE,
448 sighashTypes,
449 );
450 Promise.resolve(keyPair.sign(hash)).then(signature => {
451 const partialSig = [
452 {
453 pubkey: keyPair.publicKey,
454 signature: bscript.signature.encode(signature, sighashType),
455 },
456 ];
457 this.data.updateInput(inputIndex, { partialSig });
458 resolve();
459 });
460 });
461 }
462 toBuffer() {
463 return this.data.toBuffer();
464 }
465 toHex() {
466 return this.data.toHex();
467 }
468 toBase64() {
469 return this.data.toBase64();
470 }
471 updateGlobal(updateData) {
472 this.data.updateGlobal(updateData);
473 return this;
474 }
475 updateInput(inputIndex, updateData) {
476 this.data.updateInput(inputIndex, updateData);
477 if (updateData.nonWitnessUtxo) {
478 addNonWitnessTxCache(
479 this.__CACHE,
480 this.data.inputs[inputIndex],
481 inputIndex,
482 );
483 }
484 return this;
485 }
486 updateOutput(outputIndex, updateData) {
487 this.data.updateOutput(outputIndex, updateData);
488 return this;
489 }
490 addUnknownKeyValToGlobal(keyVal) {
491 this.data.addUnknownKeyValToGlobal(keyVal);
492 return this;
493 }
494 addUnknownKeyValToInput(inputIndex, keyVal) {
495 this.data.addUnknownKeyValToInput(inputIndex, keyVal);
496 return this;
497 }
498 addUnknownKeyValToOutput(outputIndex, keyVal) {
499 this.data.addUnknownKeyValToOutput(outputIndex, keyVal);
500 return this;
501 }
502 clearFinalizedInput(inputIndex) {
503 this.data.clearFinalizedInput(inputIndex);
504 return this;
505 }
506}
507exports.Psbt = Psbt;
508/**
509 * This function is needed to pass to the bip174 base class's fromBuffer.
510 * It takes the "transaction buffer" portion of the psbt buffer and returns a
511 * Transaction (From the bip174 library) interface.
512 */
513const transactionFromBuffer = buffer => new PsbtTransaction(buffer);
514/**
515 * This class implements the Transaction interface from bip174 library.
516 * It contains a bitcoinjs-lib Transaction object.
517 */
518class PsbtTransaction {
519 constructor(buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) {
520 this.tx = transaction_1.Transaction.fromBuffer(buffer);
521 checkTxEmpty(this.tx);
522 Object.defineProperty(this, 'tx', {
523 enumerable: false,
524 writable: true,
525 });
526 }
527 getInputOutputCounts() {
528 return {
529 inputCount: this.tx.ins.length,
530 outputCount: this.tx.outs.length,
531 };
532 }
533 addInput(input) {
534 if (
535 input.hash === undefined ||
536 input.index === undefined ||
537 (!Buffer.isBuffer(input.hash) && typeof input.hash !== 'string') ||
538 typeof input.index !== 'number'
539 ) {
540 throw new Error('Error adding input.');
541 }
542 const hash =
543 typeof input.hash === 'string'
544 ? bufferutils_1.reverseBuffer(Buffer.from(input.hash, 'hex'))
545 : input.hash;
546 this.tx.addInput(hash, input.index, input.sequence);
547 }
548 addOutput(output) {
549 if (
550 output.script === undefined ||
551 output.value === undefined ||
552 !Buffer.isBuffer(output.script) ||
553 typeof output.value !== 'number'
554 ) {
555 throw new Error('Error adding output.');
556 }
557 this.tx.addOutput(output.script, output.value);
558 }
559 toBuffer() {
560 return this.tx.toBuffer();
561 }
562}
563function canFinalize(input, script, scriptType) {
564 switch (scriptType) {
565 case 'pubkey':
566 case 'pubkeyhash':
567 case 'witnesspubkeyhash':
568 return hasSigs(1, input.partialSig);
569 case 'multisig':
570 const p2ms = payments.p2ms({ output: script });
571 return hasSigs(p2ms.m, input.partialSig);
572 default:
573 return false;
574 }
575}
576function hasSigs(neededSigs, partialSig) {
577 if (!partialSig) return false;
578 if (partialSig.length > neededSigs) throw new Error('Too many signatures');
579 return partialSig.length === neededSigs;
580}
581function isFinalized(input) {
582 return !!input.finalScriptSig || !!input.finalScriptWitness;
583}
584function isPaymentFactory(payment) {
585 return script => {
586 try {
587 payment({ output: script });
588 return true;
589 } catch (err) {
590 return false;
591 }
592 };
593}
594const isP2MS = isPaymentFactory(payments.p2ms);
595const isP2PK = isPaymentFactory(payments.p2pk);
596const isP2PKH = isPaymentFactory(payments.p2pkh);
597const isP2WPKH = isPaymentFactory(payments.p2wpkh);
598const isP2WSHScript = isPaymentFactory(payments.p2wsh);
599function check32Bit(num) {
600 if (
601 typeof num !== 'number' ||
602 num !== Math.floor(num) ||
603 num > 0xffffffff ||
604 num < 0
605 ) {
606 throw new Error('Invalid 32 bit integer');
607 }
608}
609function checkFees(psbt, cache, opts) {
610 const feeRate = cache.__FEE_RATE || psbt.getFeeRate();
611 const vsize = cache.__EXTRACTED_TX.virtualSize();
612 const satoshis = feeRate * vsize;
613 if (feeRate >= opts.maximumFeeRate) {
614 throw new Error(
615 `Warning: You are paying around ${(satoshis / 1e8).toFixed(8)} in ` +
616 `fees, which is ${feeRate} satoshi per byte for a transaction ` +
617 `with a VSize of ${vsize} bytes (segwit counted as 0.25 byte per ` +
618 `byte). Use setMaximumFeeRate method to raise your threshold, or ` +
619 `pass true to the first arg of extractTransaction.`,
620 );
621 }
622}
623function checkInputsForPartialSig(inputs, action) {
624 inputs.forEach(input => {
625 let throws = false;
626 let pSigs = [];
627 if ((input.partialSig || []).length === 0) {
628 if (!input.finalScriptSig && !input.finalScriptWitness) return;
629 pSigs = getPsigsFromInputFinalScripts(input);
630 } else {
631 pSigs = input.partialSig;
632 }
633 pSigs.forEach(pSig => {
634 const { hashType } = bscript.signature.decode(pSig.signature);
635 const whitelist = [];
636 const isAnyoneCanPay =
637 hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY;
638 if (isAnyoneCanPay) whitelist.push('addInput');
639 const hashMod = hashType & 0x1f;
640 switch (hashMod) {
641 case transaction_1.Transaction.SIGHASH_ALL:
642 break;
643 case transaction_1.Transaction.SIGHASH_SINGLE:
644 case transaction_1.Transaction.SIGHASH_NONE:
645 whitelist.push('addOutput');
646 whitelist.push('setInputSequence');
647 break;
648 }
649 if (whitelist.indexOf(action) === -1) {
650 throws = true;
651 }
652 });
653 if (throws) {
654 throw new Error('Can not modify transaction, signatures exist.');
655 }
656 });
657}
658function checkPartialSigSighashes(input) {
659 if (!input.sighashType || !input.partialSig) return;
660 const { partialSig, sighashType } = input;
661 partialSig.forEach(pSig => {
662 const { hashType } = bscript.signature.decode(pSig.signature);
663 if (sighashType !== hashType) {
664 throw new Error('Signature sighash does not match input sighash type');
665 }
666 });
667}
668function checkScriptForPubkey(pubkey, script, action) {
669 const pubkeyHash = crypto_1.hash160(pubkey);
670 const decompiled = bscript.decompile(script);
671 if (decompiled === null) throw new Error('Unknown script error');
672 const hasKey = decompiled.some(element => {
673 if (typeof element === 'number') return false;
674 return element.equals(pubkey) || element.equals(pubkeyHash);
675 });
676 if (!hasKey) {
677 throw new Error(
678 `Can not ${action} for this input with the key ${pubkey.toString('hex')}`,
679 );
680 }
681}
682function checkTxEmpty(tx) {
683 const isEmpty = tx.ins.every(
684 input =>
685 input.script &&
686 input.script.length === 0 &&
687 input.witness &&
688 input.witness.length === 0,
689 );
690 if (!isEmpty) {
691 throw new Error('Format Error: Transaction ScriptSigs are not empty');
692 }
693}
694function checkTxForDupeIns(tx, cache) {
695 tx.ins.forEach(input => {
696 checkTxInputCache(cache, input);
697 });
698}
699function checkTxInputCache(cache, input) {
700 const key =
701 bufferutils_1.reverseBuffer(Buffer.from(input.hash)).toString('hex') +
702 ':' +
703 input.index;
704 if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.');
705 cache.__TX_IN_CACHE[key] = 1;
706}
707function scriptCheckerFactory(payment, paymentScriptName) {
708 return (inputIndex, scriptPubKey, redeemScript) => {
709 const redeemScriptOutput = payment({
710 redeem: { output: redeemScript },
711 }).output;
712 if (!scriptPubKey.equals(redeemScriptOutput)) {
713 throw new Error(
714 `${paymentScriptName} for input #${inputIndex} doesn't match the scriptPubKey in the prevout`,
715 );
716 }
717 };
718}
719const checkRedeemScript = scriptCheckerFactory(payments.p2sh, 'Redeem script');
720const checkWitnessScript = scriptCheckerFactory(
721 payments.p2wsh,
722 'Witness script',
723);
724function getTxCacheValue(key, name, inputs, c) {
725 if (!inputs.every(isFinalized))
726 throw new Error(`PSBT must be finalized to calculate ${name}`);
727 if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE;
728 if (key === '__FEE' && c.__FEE) return c.__FEE;
729 let tx;
730 let mustFinalize = true;
731 if (c.__EXTRACTED_TX) {
732 tx = c.__EXTRACTED_TX;
733 mustFinalize = false;
734 } else {
735 tx = c.__TX.clone();
736 }
737 inputFinalizeGetAmts(inputs, tx, c, mustFinalize);
738 if (key === '__FEE_RATE') return c.__FEE_RATE;
739 else if (key === '__FEE') return c.__FEE;
740}
741function getFinalScripts(
742 script,
743 scriptType,
744 partialSig,
745 isSegwit,
746 isP2SH,
747 isP2WSH,
748) {
749 let finalScriptSig;
750 let finalScriptWitness;
751 // Wow, the payments API is very handy
752 const payment = getPayment(script, scriptType, partialSig);
753 const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment });
754 const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
755 if (isSegwit) {
756 if (p2wsh) {
757 finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness);
758 } else {
759 finalScriptWitness = witnessStackToScriptWitness(payment.witness);
760 }
761 if (p2sh) {
762 finalScriptSig = p2sh.input;
763 }
764 } else {
765 if (p2sh) {
766 finalScriptSig = p2sh.input;
767 } else {
768 finalScriptSig = payment.input;
769 }
770 }
771 return {
772 finalScriptSig,
773 finalScriptWitness,
774 };
775}
776function getHashAndSighashType(
777 inputs,
778 inputIndex,
779 pubkey,
780 cache,
781 sighashTypes,
782) {
783 const input = utils_1.checkForInput(inputs, inputIndex);
784 const { hash, sighashType, script } = getHashForSig(
785 inputIndex,
786 input,
787 cache,
788 sighashTypes,
789 );
790 checkScriptForPubkey(pubkey, script, 'sign');
791 return {
792 hash,
793 sighashType,
794 };
795}
796function getHashForSig(inputIndex, input, cache, sighashTypes) {
797 const unsignedTx = cache.__TX;
798 const sighashType =
799 input.sighashType || transaction_1.Transaction.SIGHASH_ALL;
800 if (sighashTypes && sighashTypes.indexOf(sighashType) < 0) {
801 const str = sighashTypeToString(sighashType);
802 throw new Error(
803 `Sighash type is not allowed. Retry the sign method passing the ` +
804 `sighashTypes array of whitelisted types. Sighash type: ${str}`,
805 );
806 }
807 let hash;
808 let script;
809 if (input.nonWitnessUtxo) {
810 const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
811 cache,
812 input,
813 inputIndex,
814 );
815 const prevoutHash = unsignedTx.ins[inputIndex].hash;
816 const utxoHash = nonWitnessUtxoTx.getHash();
817 // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout
818 if (!prevoutHash.equals(utxoHash)) {
819 throw new Error(
820 `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`,
821 );
822 }
823 const prevoutIndex = unsignedTx.ins[inputIndex].index;
824 const prevout = nonWitnessUtxoTx.outs[prevoutIndex];
825 if (input.redeemScript) {
826 // If a redeemScript is provided, the scriptPubKey must be for that redeemScript
827 checkRedeemScript(inputIndex, prevout.script, input.redeemScript);
828 script = input.redeemScript;
829 } else {
830 script = prevout.script;
831 }
832 if (isP2WSHScript(script)) {
833 if (!input.witnessScript)
834 throw new Error('Segwit input needs witnessScript if not P2WPKH');
835 checkWitnessScript(inputIndex, script, input.witnessScript);
836 hash = unsignedTx.hashForWitnessV0(
837 inputIndex,
838 input.witnessScript,
839 prevout.value,
840 sighashType,
841 );
842 script = input.witnessScript;
843 } else if (isP2WPKH(script)) {
844 // P2WPKH uses the P2PKH template for prevoutScript when signing
845 const signingScript = payments.p2pkh({ hash: script.slice(2) }).output;
846 hash = unsignedTx.hashForWitnessV0(
847 inputIndex,
848 signingScript,
849 prevout.value,
850 sighashType,
851 );
852 } else {
853 hash = unsignedTx.hashForSignature(inputIndex, script, sighashType);
854 }
855 } else if (input.witnessUtxo) {
856 let _script; // so we don't shadow the `let script` above
857 if (input.redeemScript) {
858 // If a redeemScript is provided, the scriptPubKey must be for that redeemScript
859 checkRedeemScript(
860 inputIndex,
861 input.witnessUtxo.script,
862 input.redeemScript,
863 );
864 _script = input.redeemScript;
865 } else {
866 _script = input.witnessUtxo.script;
867 }
868 if (isP2WPKH(_script)) {
869 // P2WPKH uses the P2PKH template for prevoutScript when signing
870 const signingScript = payments.p2pkh({ hash: _script.slice(2) }).output;
871 hash = unsignedTx.hashForWitnessV0(
872 inputIndex,
873 signingScript,
874 input.witnessUtxo.value,
875 sighashType,
876 );
877 script = _script;
878 } else if (isP2WSHScript(_script)) {
879 if (!input.witnessScript)
880 throw new Error('Segwit input needs witnessScript if not P2WPKH');
881 checkWitnessScript(inputIndex, _script, input.witnessScript);
882 hash = unsignedTx.hashForWitnessV0(
883 inputIndex,
884 input.witnessScript,
885 input.witnessUtxo.value,
886 sighashType,
887 );
888 // want to make sure the script we return is the actual meaningful script
889 script = input.witnessScript;
890 } else {
891 throw new Error(
892 `Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
893 `${_script.toString('hex')}`,
894 );
895 }
896 } else {
897 throw new Error('Need a Utxo input item for signing');
898 }
899 return {
900 script,
901 sighashType,
902 hash,
903 };
904}
905function getPayment(script, scriptType, partialSig) {
906 let payment;
907 switch (scriptType) {
908 case 'multisig':
909 const sigs = getSortedSigs(script, partialSig);
910 payment = payments.p2ms({
911 output: script,
912 signatures: sigs,
913 });
914 break;
915 case 'pubkey':
916 payment = payments.p2pk({
917 output: script,
918 signature: partialSig[0].signature,
919 });
920 break;
921 case 'pubkeyhash':
922 payment = payments.p2pkh({
923 output: script,
924 pubkey: partialSig[0].pubkey,
925 signature: partialSig[0].signature,
926 });
927 break;
928 case 'witnesspubkeyhash':
929 payment = payments.p2wpkh({
930 output: script,
931 pubkey: partialSig[0].pubkey,
932 signature: partialSig[0].signature,
933 });
934 break;
935 }
936 return payment;
937}
938function getPsigsFromInputFinalScripts(input) {
939 const scriptItems = !input.finalScriptSig
940 ? []
941 : bscript.decompile(input.finalScriptSig) || [];
942 const witnessItems = !input.finalScriptWitness
943 ? []
944 : bscript.decompile(input.finalScriptWitness) || [];
945 return scriptItems
946 .concat(witnessItems)
947 .filter(item => {
948 return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item);
949 })
950 .map(sig => ({ signature: sig }));
951}
952function getScriptFromInput(inputIndex, input, cache) {
953 const unsignedTx = cache.__TX;
954 const res = {
955 script: null,
956 isSegwit: false,
957 isP2SH: false,
958 isP2WSH: false,
959 };
960 res.isP2SH = !!input.redeemScript;
961 res.isP2WSH = !!input.witnessScript;
962 if (input.witnessScript) {
963 res.script = input.witnessScript;
964 } else if (input.redeemScript) {
965 res.script = input.redeemScript;
966 } else {
967 if (input.nonWitnessUtxo) {
968 const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
969 cache,
970 input,
971 inputIndex,
972 );
973 const prevoutIndex = unsignedTx.ins[inputIndex].index;
974 res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;
975 } else if (input.witnessUtxo) {
976 res.script = input.witnessUtxo.script;
977 }
978 }
979 if (input.witnessScript || isP2WPKH(res.script)) {
980 res.isSegwit = true;
981 }
982 return res;
983}
984function getSignersFromHD(inputIndex, inputs, hdKeyPair) {
985 const input = utils_1.checkForInput(inputs, inputIndex);
986 if (!input.bip32Derivation || input.bip32Derivation.length === 0) {
987 throw new Error('Need bip32Derivation to sign with HD');
988 }
989 const myDerivations = input.bip32Derivation
990 .map(bipDv => {
991 if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) {
992 return bipDv;
993 } else {
994 return;
995 }
996 })
997 .filter(v => !!v);
998 if (myDerivations.length === 0) {
999 throw new Error(
1000 'Need one bip32Derivation masterFingerprint to match the HDSigner fingerprint',
1001 );
1002 }
1003 const signers = myDerivations.map(bipDv => {
1004 const node = hdKeyPair.derivePath(bipDv.path);
1005 if (!bipDv.pubkey.equals(node.publicKey)) {
1006 throw new Error('pubkey did not match bip32Derivation');
1007 }
1008 return node;
1009 });
1010 return signers;
1011}
1012function getSortedSigs(script, partialSig) {
1013 const p2ms = payments.p2ms({ output: script });
1014 // for each pubkey in order of p2ms script
1015 return p2ms.pubkeys
1016 .map(pk => {
1017 // filter partialSig array by pubkey being equal
1018 return (
1019 partialSig.filter(ps => {
1020 return ps.pubkey.equals(pk);
1021 })[0] || {}
1022 ).signature;
1023 // Any pubkey without a match will return undefined
1024 // this last filter removes all the undefined items in the array.
1025 })
1026 .filter(v => !!v);
1027}
1028function scriptWitnessToWitnessStack(buffer) {
1029 let offset = 0;
1030 function readSlice(n) {
1031 offset += n;
1032 return buffer.slice(offset - n, offset);
1033 }
1034 function readVarInt() {
1035 const vi = varuint.decode(buffer, offset);
1036 offset += varuint.decode.bytes;
1037 return vi;
1038 }
1039 function readVarSlice() {
1040 return readSlice(readVarInt());
1041 }
1042 function readVector() {
1043 const count = readVarInt();
1044 const vector = [];
1045 for (let i = 0; i < count; i++) vector.push(readVarSlice());
1046 return vector;
1047 }
1048 return readVector();
1049}
1050function sighashTypeToString(sighashType) {
1051 let text =
1052 sighashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY
1053 ? 'SIGHASH_ANYONECANPAY | '
1054 : '';
1055 const sigMod = sighashType & 0x1f;
1056 switch (sigMod) {
1057 case transaction_1.Transaction.SIGHASH_ALL:
1058 text += 'SIGHASH_ALL';
1059 break;
1060 case transaction_1.Transaction.SIGHASH_SINGLE:
1061 text += 'SIGHASH_SINGLE';
1062 break;
1063 case transaction_1.Transaction.SIGHASH_NONE:
1064 text += 'SIGHASH_NONE';
1065 break;
1066 }
1067 return text;
1068}
1069function witnessStackToScriptWitness(witness) {
1070 let buffer = Buffer.allocUnsafe(0);
1071 function writeSlice(slice) {
1072 buffer = Buffer.concat([buffer, Buffer.from(slice)]);
1073 }
1074 function writeVarInt(i) {
1075 const currentLen = buffer.length;
1076 const varintLen = varuint.encodingLength(i);
1077 buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
1078 varuint.encode(i, buffer, currentLen);
1079 }
1080 function writeVarSlice(slice) {
1081 writeVarInt(slice.length);
1082 writeSlice(slice);
1083 }
1084 function writeVector(vector) {
1085 writeVarInt(vector.length);
1086 vector.forEach(writeVarSlice);
1087 }
1088 writeVector(witness);
1089 return buffer;
1090}
1091function addNonWitnessTxCache(cache, input, inputIndex) {
1092 cache.__NON_WITNESS_UTXO_BUF_CACHE[inputIndex] = input.nonWitnessUtxo;
1093 const tx = transaction_1.Transaction.fromBuffer(input.nonWitnessUtxo);
1094 cache.__NON_WITNESS_UTXO_TX_CACHE[inputIndex] = tx;
1095 const self = cache;
1096 const selfIndex = inputIndex;
1097 delete input.nonWitnessUtxo;
1098 Object.defineProperty(input, 'nonWitnessUtxo', {
1099 enumerable: true,
1100 get() {
1101 const buf = self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex];
1102 const txCache = self.__NON_WITNESS_UTXO_TX_CACHE[selfIndex];
1103 if (buf !== undefined) {
1104 return buf;
1105 } else {
1106 const newBuf = txCache.toBuffer();
1107 self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = newBuf;
1108 return newBuf;
1109 }
1110 },
1111 set(data) {
1112 self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = data;
1113 },
1114 });
1115}
1116function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) {
1117 let inputAmount = 0;
1118 inputs.forEach((input, idx) => {
1119 if (mustFinalize && input.finalScriptSig)
1120 tx.ins[idx].script = input.finalScriptSig;
1121 if (mustFinalize && input.finalScriptWitness) {
1122 tx.ins[idx].witness = scriptWitnessToWitnessStack(
1123 input.finalScriptWitness,
1124 );
1125 }
1126 if (input.witnessUtxo) {
1127 inputAmount += input.witnessUtxo.value;
1128 } else if (input.nonWitnessUtxo) {
1129 const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx);
1130 const vout = tx.ins[idx].index;
1131 const out = nwTx.outs[vout];
1132 inputAmount += out.value;
1133 }
1134 });
1135 const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0);
1136 const fee = inputAmount - outputAmount;
1137 if (fee < 0) {
1138 throw new Error('Outputs are spending more than Inputs');
1139 }
1140 const bytes = tx.virtualSize();
1141 cache.__FEE = fee;
1142 cache.__EXTRACTED_TX = tx;
1143 cache.__FEE_RATE = Math.floor(fee / bytes);
1144}
1145function nonWitnessUtxoTxFromCache(cache, input, inputIndex) {
1146 const c = cache.__NON_WITNESS_UTXO_TX_CACHE;
1147 if (!c[inputIndex]) {
1148 addNonWitnessTxCache(cache, input, inputIndex);
1149 }
1150 return c[inputIndex];
1151}
1152function classifyScript(script) {
1153 if (isP2WPKH(script)) return 'witnesspubkeyhash';
1154 if (isP2PKH(script)) return 'pubkeyhash';
1155 if (isP2MS(script)) return 'multisig';
1156 if (isP2PK(script)) return 'pubkey';
1157 return 'nonstandard';
1158}
1159function range(n) {
1160 return [...Array(n).keys()];
1161}