UNPKG

33.4 kBJavaScriptView Raw
1'use strict';
2Object.defineProperty(exports, '__esModule', { value: true });
3const baddress = require('./address');
4const bufferutils_1 = require('./bufferutils');
5const classify = require('./classify');
6const bcrypto = require('./crypto');
7const ECPair = require('./ecpair');
8const networks = require('./networks');
9const payments = require('./payments');
10const bscript = require('./script');
11const script_1 = require('./script');
12const transaction_1 = require('./transaction');
13const types = require('./types');
14const typeforce = require('typeforce');
15const SCRIPT_TYPES = classify.types;
16const PREVOUT_TYPES = new Set([
17 // Raw
18 'p2pkh',
19 'p2pk',
20 'p2wpkh',
21 'p2ms',
22 // P2SH wrapped
23 'p2sh-p2pkh',
24 'p2sh-p2pk',
25 'p2sh-p2wpkh',
26 'p2sh-p2ms',
27 // P2WSH wrapped
28 'p2wsh-p2pkh',
29 'p2wsh-p2pk',
30 'p2wsh-p2ms',
31 // P2SH-P2WSH wrapper
32 'p2sh-p2wsh-p2pkh',
33 'p2sh-p2wsh-p2pk',
34 'p2sh-p2wsh-p2ms',
35]);
36function tfMessage(type, value, message) {
37 try {
38 typeforce(type, value);
39 } catch (err) {
40 throw new Error(message);
41 }
42}
43function txIsString(tx) {
44 return typeof tx === 'string' || tx instanceof String;
45}
46function txIsTransaction(tx) {
47 return tx instanceof transaction_1.Transaction;
48}
49class TransactionBuilder {
50 // WARNING: maximumFeeRate is __NOT__ to be relied on,
51 // it's just another potential safety mechanism (safety in-depth)
52 constructor(network = networks.bitcoin, maximumFeeRate = 2500) {
53 this.network = network;
54 this.maximumFeeRate = maximumFeeRate;
55 this.__PREV_TX_SET = {};
56 this.__INPUTS = [];
57 this.__TX = new transaction_1.Transaction();
58 this.__TX.version = 2;
59 this.__USE_LOW_R = false;
60 console.warn(
61 'Deprecation Warning: TransactionBuilder will be removed in the future. ' +
62 '(v6.x.x or later) Please use the Psbt class instead. Examples of usage ' +
63 'are available in the transactions-psbt.js integration test file on our ' +
64 'Github. A high level explanation is available in the psbt.ts and psbt.js ' +
65 'files as well.',
66 );
67 }
68 static fromTransaction(transaction, network) {
69 const txb = new TransactionBuilder(network);
70 // Copy transaction fields
71 txb.setVersion(transaction.version);
72 txb.setLockTime(transaction.locktime);
73 // Copy outputs (done first to avoid signature invalidation)
74 transaction.outs.forEach(txOut => {
75 txb.addOutput(txOut.script, txOut.value);
76 });
77 // Copy inputs
78 transaction.ins.forEach(txIn => {
79 txb.__addInputUnsafe(txIn.hash, txIn.index, {
80 sequence: txIn.sequence,
81 script: txIn.script,
82 witness: txIn.witness,
83 });
84 });
85 // fix some things not possible through the public API
86 txb.__INPUTS.forEach((input, i) => {
87 fixMultisigOrder(input, transaction, i);
88 });
89 return txb;
90 }
91 setLowR(setting) {
92 typeforce(typeforce.maybe(typeforce.Boolean), setting);
93 if (setting === undefined) {
94 setting = true;
95 }
96 this.__USE_LOW_R = setting;
97 return setting;
98 }
99 setLockTime(locktime) {
100 typeforce(types.UInt32, locktime);
101 // if any signatures exist, throw
102 if (
103 this.__INPUTS.some(input => {
104 if (!input.signatures) return false;
105 return input.signatures.some(s => s !== undefined);
106 })
107 ) {
108 throw new Error('No, this would invalidate signatures');
109 }
110 this.__TX.locktime = locktime;
111 }
112 setVersion(version) {
113 typeforce(types.UInt32, version);
114 // XXX: this might eventually become more complex depending on what the versions represent
115 this.__TX.version = version;
116 }
117 addInput(txHash, vout, sequence, prevOutScript) {
118 if (!this.__canModifyInputs()) {
119 throw new Error('No, this would invalidate signatures');
120 }
121 let value;
122 // is it a hex string?
123 if (txIsString(txHash)) {
124 // transaction hashs's are displayed in reverse order, un-reverse it
125 txHash = bufferutils_1.reverseBuffer(Buffer.from(txHash, 'hex'));
126 // is it a Transaction object?
127 } else if (txIsTransaction(txHash)) {
128 const txOut = txHash.outs[vout];
129 prevOutScript = txOut.script;
130 value = txOut.value;
131 txHash = txHash.getHash(false);
132 }
133 return this.__addInputUnsafe(txHash, vout, {
134 sequence,
135 prevOutScript,
136 value,
137 });
138 }
139 addOutput(scriptPubKey, value) {
140 if (!this.__canModifyOutputs()) {
141 throw new Error('No, this would invalidate signatures');
142 }
143 // Attempt to get a script if it's a base58 or bech32 address string
144 if (typeof scriptPubKey === 'string') {
145 scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network);
146 }
147 return this.__TX.addOutput(scriptPubKey, value);
148 }
149 build() {
150 return this.__build(false);
151 }
152 buildIncomplete() {
153 return this.__build(true);
154 }
155 sign(
156 signParams,
157 keyPair,
158 redeemScript,
159 hashType,
160 witnessValue,
161 witnessScript,
162 ) {
163 trySign(
164 getSigningData(
165 this.network,
166 this.__INPUTS,
167 this.__needsOutputs.bind(this),
168 this.__TX,
169 signParams,
170 keyPair,
171 redeemScript,
172 hashType,
173 witnessValue,
174 witnessScript,
175 this.__USE_LOW_R,
176 ),
177 );
178 }
179 __addInputUnsafe(txHash, vout, options) {
180 if (transaction_1.Transaction.isCoinbaseHash(txHash)) {
181 throw new Error('coinbase inputs not supported');
182 }
183 const prevTxOut = txHash.toString('hex') + ':' + vout;
184 if (this.__PREV_TX_SET[prevTxOut] !== undefined)
185 throw new Error('Duplicate TxOut: ' + prevTxOut);
186 let input = {};
187 // derive what we can from the scriptSig
188 if (options.script !== undefined) {
189 input = expandInput(options.script, options.witness || []);
190 }
191 // if an input value was given, retain it
192 if (options.value !== undefined) {
193 input.value = options.value;
194 }
195 // derive what we can from the previous transactions output script
196 if (!input.prevOutScript && options.prevOutScript) {
197 let prevOutType;
198 if (!input.pubkeys && !input.signatures) {
199 const expanded = expandOutput(options.prevOutScript);
200 if (expanded.pubkeys) {
201 input.pubkeys = expanded.pubkeys;
202 input.signatures = expanded.signatures;
203 }
204 prevOutType = expanded.type;
205 }
206 input.prevOutScript = options.prevOutScript;
207 input.prevOutType = prevOutType || classify.output(options.prevOutScript);
208 }
209 const vin = this.__TX.addInput(
210 txHash,
211 vout,
212 options.sequence,
213 options.scriptSig,
214 );
215 this.__INPUTS[vin] = input;
216 this.__PREV_TX_SET[prevTxOut] = true;
217 return vin;
218 }
219 __build(allowIncomplete) {
220 if (!allowIncomplete) {
221 if (!this.__TX.ins.length) throw new Error('Transaction has no inputs');
222 if (!this.__TX.outs.length) throw new Error('Transaction has no outputs');
223 }
224 const tx = this.__TX.clone();
225 // create script signatures from inputs
226 this.__INPUTS.forEach((input, i) => {
227 if (!input.prevOutType && !allowIncomplete)
228 throw new Error('Transaction is not complete');
229 const result = build(input.prevOutType, input, allowIncomplete);
230 if (!result) {
231 if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD)
232 throw new Error('Unknown input type');
233 if (!allowIncomplete) throw new Error('Not enough information');
234 return;
235 }
236 tx.setInputScript(i, result.input);
237 tx.setWitness(i, result.witness);
238 });
239 if (!allowIncomplete) {
240 // do not rely on this, its merely a last resort
241 if (this.__overMaximumFees(tx.virtualSize())) {
242 throw new Error('Transaction has absurd fees');
243 }
244 }
245 return tx;
246 }
247 __canModifyInputs() {
248 return this.__INPUTS.every(input => {
249 if (!input.signatures) return true;
250 return input.signatures.every(signature => {
251 if (!signature) return true;
252 const hashType = signatureHashType(signature);
253 // if SIGHASH_ANYONECANPAY is set, signatures would not
254 // be invalidated by more inputs
255 return (
256 (hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY) !== 0
257 );
258 });
259 });
260 }
261 __needsOutputs(signingHashType) {
262 if (signingHashType === transaction_1.Transaction.SIGHASH_ALL) {
263 return this.__TX.outs.length === 0;
264 }
265 // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs
266 // .build() will fail, but .buildIncomplete() is OK
267 return (
268 this.__TX.outs.length === 0 &&
269 this.__INPUTS.some(input => {
270 if (!input.signatures) return false;
271 return input.signatures.some(signature => {
272 if (!signature) return false; // no signature, no issue
273 const hashType = signatureHashType(signature);
274 if (hashType & transaction_1.Transaction.SIGHASH_NONE) return false; // SIGHASH_NONE doesn't care about outputs
275 return true; // SIGHASH_* does care
276 });
277 })
278 );
279 }
280 __canModifyOutputs() {
281 const nInputs = this.__TX.ins.length;
282 const nOutputs = this.__TX.outs.length;
283 return this.__INPUTS.every(input => {
284 if (input.signatures === undefined) return true;
285 return input.signatures.every(signature => {
286 if (!signature) return true;
287 const hashType = signatureHashType(signature);
288 const hashTypeMod = hashType & 0x1f;
289 if (hashTypeMod === transaction_1.Transaction.SIGHASH_NONE) return true;
290 if (hashTypeMod === transaction_1.Transaction.SIGHASH_SINGLE) {
291 // if SIGHASH_SINGLE is set, and nInputs > nOutputs
292 // some signatures would be invalidated by the addition
293 // of more outputs
294 return nInputs <= nOutputs;
295 }
296 return false;
297 });
298 });
299 }
300 __overMaximumFees(bytes) {
301 // not all inputs will have .value defined
302 const incoming = this.__INPUTS.reduce((a, x) => a + (x.value >>> 0), 0);
303 // but all outputs do, and if we have any input value
304 // we can immediately determine if the outputs are too small
305 const outgoing = this.__TX.outs.reduce((a, x) => a + x.value, 0);
306 const fee = incoming - outgoing;
307 const feeRate = fee / bytes;
308 return feeRate > this.maximumFeeRate;
309 }
310}
311exports.TransactionBuilder = TransactionBuilder;
312function expandInput(scriptSig, witnessStack, type, scriptPubKey) {
313 if (scriptSig.length === 0 && witnessStack.length === 0) return {};
314 if (!type) {
315 let ssType = classify.input(scriptSig, true);
316 let wsType = classify.witness(witnessStack, true);
317 if (ssType === SCRIPT_TYPES.NONSTANDARD) ssType = undefined;
318 if (wsType === SCRIPT_TYPES.NONSTANDARD) wsType = undefined;
319 type = ssType || wsType;
320 }
321 switch (type) {
322 case SCRIPT_TYPES.P2WPKH: {
323 const { output, pubkey, signature } = payments.p2wpkh({
324 witness: witnessStack,
325 });
326 return {
327 prevOutScript: output,
328 prevOutType: SCRIPT_TYPES.P2WPKH,
329 pubkeys: [pubkey],
330 signatures: [signature],
331 };
332 }
333 case SCRIPT_TYPES.P2PKH: {
334 const { output, pubkey, signature } = payments.p2pkh({
335 input: scriptSig,
336 });
337 return {
338 prevOutScript: output,
339 prevOutType: SCRIPT_TYPES.P2PKH,
340 pubkeys: [pubkey],
341 signatures: [signature],
342 };
343 }
344 case SCRIPT_TYPES.P2PK: {
345 const { signature } = payments.p2pk({ input: scriptSig });
346 return {
347 prevOutType: SCRIPT_TYPES.P2PK,
348 pubkeys: [undefined],
349 signatures: [signature],
350 };
351 }
352 case SCRIPT_TYPES.P2MS: {
353 const { m, pubkeys, signatures } = payments.p2ms(
354 {
355 input: scriptSig,
356 output: scriptPubKey,
357 },
358 { allowIncomplete: true },
359 );
360 return {
361 prevOutType: SCRIPT_TYPES.P2MS,
362 pubkeys,
363 signatures,
364 maxSignatures: m,
365 };
366 }
367 }
368 if (type === SCRIPT_TYPES.P2SH) {
369 const { output, redeem } = payments.p2sh({
370 input: scriptSig,
371 witness: witnessStack,
372 });
373 const outputType = classify.output(redeem.output);
374 const expanded = expandInput(
375 redeem.input,
376 redeem.witness,
377 outputType,
378 redeem.output,
379 );
380 if (!expanded.prevOutType) return {};
381 return {
382 prevOutScript: output,
383 prevOutType: SCRIPT_TYPES.P2SH,
384 redeemScript: redeem.output,
385 redeemScriptType: expanded.prevOutType,
386 witnessScript: expanded.witnessScript,
387 witnessScriptType: expanded.witnessScriptType,
388 pubkeys: expanded.pubkeys,
389 signatures: expanded.signatures,
390 };
391 }
392 if (type === SCRIPT_TYPES.P2WSH) {
393 const { output, redeem } = payments.p2wsh({
394 input: scriptSig,
395 witness: witnessStack,
396 });
397 const outputType = classify.output(redeem.output);
398 let expanded;
399 if (outputType === SCRIPT_TYPES.P2WPKH) {
400 expanded = expandInput(redeem.input, redeem.witness, outputType);
401 } else {
402 expanded = expandInput(
403 bscript.compile(redeem.witness),
404 [],
405 outputType,
406 redeem.output,
407 );
408 }
409 if (!expanded.prevOutType) return {};
410 return {
411 prevOutScript: output,
412 prevOutType: SCRIPT_TYPES.P2WSH,
413 witnessScript: redeem.output,
414 witnessScriptType: expanded.prevOutType,
415 pubkeys: expanded.pubkeys,
416 signatures: expanded.signatures,
417 };
418 }
419 return {
420 prevOutType: SCRIPT_TYPES.NONSTANDARD,
421 prevOutScript: scriptSig,
422 };
423}
424// could be done in expandInput, but requires the original Transaction for hashForSignature
425function fixMultisigOrder(input, transaction, vin) {
426 if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript)
427 return;
428 if (input.pubkeys.length === input.signatures.length) return;
429 const unmatched = input.signatures.concat();
430 input.signatures = input.pubkeys.map(pubKey => {
431 const keyPair = ECPair.fromPublicKey(pubKey);
432 let match;
433 // check for a signature
434 unmatched.some((signature, i) => {
435 // skip if undefined || OP_0
436 if (!signature) return false;
437 // TODO: avoid O(n) hashForSignature
438 const parsed = bscript.signature.decode(signature);
439 const hash = transaction.hashForSignature(
440 vin,
441 input.redeemScript,
442 parsed.hashType,
443 );
444 // skip if signature does not match pubKey
445 if (!keyPair.verify(hash, parsed.signature)) return false;
446 // remove matched signature from unmatched
447 unmatched[i] = undefined;
448 match = signature;
449 return true;
450 });
451 return match;
452 });
453}
454function expandOutput(script, ourPubKey) {
455 typeforce(types.Buffer, script);
456 const type = classify.output(script);
457 switch (type) {
458 case SCRIPT_TYPES.P2PKH: {
459 if (!ourPubKey) return { type };
460 // does our hash160(pubKey) match the output scripts?
461 const pkh1 = payments.p2pkh({ output: script }).hash;
462 const pkh2 = bcrypto.hash160(ourPubKey);
463 if (!pkh1.equals(pkh2)) return { type };
464 return {
465 type,
466 pubkeys: [ourPubKey],
467 signatures: [undefined],
468 };
469 }
470 case SCRIPT_TYPES.P2WPKH: {
471 if (!ourPubKey) return { type };
472 // does our hash160(pubKey) match the output scripts?
473 const wpkh1 = payments.p2wpkh({ output: script }).hash;
474 const wpkh2 = bcrypto.hash160(ourPubKey);
475 if (!wpkh1.equals(wpkh2)) return { type };
476 return {
477 type,
478 pubkeys: [ourPubKey],
479 signatures: [undefined],
480 };
481 }
482 case SCRIPT_TYPES.P2PK: {
483 const p2pk = payments.p2pk({ output: script });
484 return {
485 type,
486 pubkeys: [p2pk.pubkey],
487 signatures: [undefined],
488 };
489 }
490 case SCRIPT_TYPES.P2MS: {
491 const p2ms = payments.p2ms({ output: script });
492 return {
493 type,
494 pubkeys: p2ms.pubkeys,
495 signatures: p2ms.pubkeys.map(() => undefined),
496 maxSignatures: p2ms.m,
497 };
498 }
499 }
500 return { type };
501}
502function prepareInput(input, ourPubKey, redeemScript, witnessScript) {
503 if (redeemScript && witnessScript) {
504 const p2wsh = payments.p2wsh({
505 redeem: { output: witnessScript },
506 });
507 const p2wshAlt = payments.p2wsh({ output: redeemScript });
508 const p2sh = payments.p2sh({ redeem: { output: redeemScript } });
509 const p2shAlt = payments.p2sh({ redeem: p2wsh });
510 // enforces P2SH(P2WSH(...))
511 if (!p2wsh.hash.equals(p2wshAlt.hash))
512 throw new Error('Witness script inconsistent with prevOutScript');
513 if (!p2sh.hash.equals(p2shAlt.hash))
514 throw new Error('Redeem script inconsistent with prevOutScript');
515 const expanded = expandOutput(p2wsh.redeem.output, ourPubKey);
516 if (!expanded.pubkeys)
517 throw new Error(
518 expanded.type +
519 ' not supported as witnessScript (' +
520 bscript.toASM(witnessScript) +
521 ')',
522 );
523 if (input.signatures && input.signatures.some(x => x !== undefined)) {
524 expanded.signatures = input.signatures;
525 }
526 const signScript = witnessScript;
527 if (expanded.type === SCRIPT_TYPES.P2WPKH)
528 throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure');
529 return {
530 redeemScript,
531 redeemScriptType: SCRIPT_TYPES.P2WSH,
532 witnessScript,
533 witnessScriptType: expanded.type,
534 prevOutType: SCRIPT_TYPES.P2SH,
535 prevOutScript: p2sh.output,
536 hasWitness: true,
537 signScript,
538 signType: expanded.type,
539 pubkeys: expanded.pubkeys,
540 signatures: expanded.signatures,
541 maxSignatures: expanded.maxSignatures,
542 };
543 }
544 if (redeemScript) {
545 const p2sh = payments.p2sh({ redeem: { output: redeemScript } });
546 if (input.prevOutScript) {
547 let p2shAlt;
548 try {
549 p2shAlt = payments.p2sh({ output: input.prevOutScript });
550 } catch (e) {
551 throw new Error('PrevOutScript must be P2SH');
552 }
553 if (!p2sh.hash.equals(p2shAlt.hash))
554 throw new Error('Redeem script inconsistent with prevOutScript');
555 }
556 const expanded = expandOutput(p2sh.redeem.output, ourPubKey);
557 if (!expanded.pubkeys)
558 throw new Error(
559 expanded.type +
560 ' not supported as redeemScript (' +
561 bscript.toASM(redeemScript) +
562 ')',
563 );
564 if (input.signatures && input.signatures.some(x => x !== undefined)) {
565 expanded.signatures = input.signatures;
566 }
567 let signScript = redeemScript;
568 if (expanded.type === SCRIPT_TYPES.P2WPKH) {
569 signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output;
570 }
571 return {
572 redeemScript,
573 redeemScriptType: expanded.type,
574 prevOutType: SCRIPT_TYPES.P2SH,
575 prevOutScript: p2sh.output,
576 hasWitness: expanded.type === SCRIPT_TYPES.P2WPKH,
577 signScript,
578 signType: expanded.type,
579 pubkeys: expanded.pubkeys,
580 signatures: expanded.signatures,
581 maxSignatures: expanded.maxSignatures,
582 };
583 }
584 if (witnessScript) {
585 const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } });
586 if (input.prevOutScript) {
587 const p2wshAlt = payments.p2wsh({ output: input.prevOutScript });
588 if (!p2wsh.hash.equals(p2wshAlt.hash))
589 throw new Error('Witness script inconsistent with prevOutScript');
590 }
591 const expanded = expandOutput(p2wsh.redeem.output, ourPubKey);
592 if (!expanded.pubkeys)
593 throw new Error(
594 expanded.type +
595 ' not supported as witnessScript (' +
596 bscript.toASM(witnessScript) +
597 ')',
598 );
599 if (input.signatures && input.signatures.some(x => x !== undefined)) {
600 expanded.signatures = input.signatures;
601 }
602 const signScript = witnessScript;
603 if (expanded.type === SCRIPT_TYPES.P2WPKH)
604 throw new Error('P2WSH(P2WPKH) is a consensus failure');
605 return {
606 witnessScript,
607 witnessScriptType: expanded.type,
608 prevOutType: SCRIPT_TYPES.P2WSH,
609 prevOutScript: p2wsh.output,
610 hasWitness: true,
611 signScript,
612 signType: expanded.type,
613 pubkeys: expanded.pubkeys,
614 signatures: expanded.signatures,
615 maxSignatures: expanded.maxSignatures,
616 };
617 }
618 if (input.prevOutType && input.prevOutScript) {
619 // embedded scripts are not possible without extra information
620 if (input.prevOutType === SCRIPT_TYPES.P2SH)
621 throw new Error(
622 'PrevOutScript is ' + input.prevOutType + ', requires redeemScript',
623 );
624 if (input.prevOutType === SCRIPT_TYPES.P2WSH)
625 throw new Error(
626 'PrevOutScript is ' + input.prevOutType + ', requires witnessScript',
627 );
628 if (!input.prevOutScript) throw new Error('PrevOutScript is missing');
629 const expanded = expandOutput(input.prevOutScript, ourPubKey);
630 if (!expanded.pubkeys)
631 throw new Error(
632 expanded.type +
633 ' not supported (' +
634 bscript.toASM(input.prevOutScript) +
635 ')',
636 );
637 if (input.signatures && input.signatures.some(x => x !== undefined)) {
638 expanded.signatures = input.signatures;
639 }
640 let signScript = input.prevOutScript;
641 if (expanded.type === SCRIPT_TYPES.P2WPKH) {
642 signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output;
643 }
644 return {
645 prevOutType: expanded.type,
646 prevOutScript: input.prevOutScript,
647 hasWitness: expanded.type === SCRIPT_TYPES.P2WPKH,
648 signScript,
649 signType: expanded.type,
650 pubkeys: expanded.pubkeys,
651 signatures: expanded.signatures,
652 maxSignatures: expanded.maxSignatures,
653 };
654 }
655 const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output;
656 return {
657 prevOutType: SCRIPT_TYPES.P2PKH,
658 prevOutScript,
659 hasWitness: false,
660 signScript: prevOutScript,
661 signType: SCRIPT_TYPES.P2PKH,
662 pubkeys: [ourPubKey],
663 signatures: [undefined],
664 };
665}
666function build(type, input, allowIncomplete) {
667 const pubkeys = input.pubkeys || [];
668 let signatures = input.signatures || [];
669 switch (type) {
670 case SCRIPT_TYPES.P2PKH: {
671 if (pubkeys.length === 0) break;
672 if (signatures.length === 0) break;
673 return payments.p2pkh({ pubkey: pubkeys[0], signature: signatures[0] });
674 }
675 case SCRIPT_TYPES.P2WPKH: {
676 if (pubkeys.length === 0) break;
677 if (signatures.length === 0) break;
678 return payments.p2wpkh({ pubkey: pubkeys[0], signature: signatures[0] });
679 }
680 case SCRIPT_TYPES.P2PK: {
681 if (pubkeys.length === 0) break;
682 if (signatures.length === 0) break;
683 return payments.p2pk({ signature: signatures[0] });
684 }
685 case SCRIPT_TYPES.P2MS: {
686 const m = input.maxSignatures;
687 if (allowIncomplete) {
688 signatures = signatures.map(x => x || script_1.OPS.OP_0);
689 } else {
690 signatures = signatures.filter(x => x);
691 }
692 // if the transaction is not not complete (complete), or if signatures.length === m, validate
693 // otherwise, the number of OP_0's may be >= m, so don't validate (boo)
694 const validate = !allowIncomplete || m === signatures.length;
695 return payments.p2ms(
696 { m, pubkeys, signatures },
697 { allowIncomplete, validate },
698 );
699 }
700 case SCRIPT_TYPES.P2SH: {
701 const redeem = build(input.redeemScriptType, input, allowIncomplete);
702 if (!redeem) return;
703 return payments.p2sh({
704 redeem: {
705 output: redeem.output || input.redeemScript,
706 input: redeem.input,
707 witness: redeem.witness,
708 },
709 });
710 }
711 case SCRIPT_TYPES.P2WSH: {
712 const redeem = build(input.witnessScriptType, input, allowIncomplete);
713 if (!redeem) return;
714 return payments.p2wsh({
715 redeem: {
716 output: input.witnessScript,
717 input: redeem.input,
718 witness: redeem.witness,
719 },
720 });
721 }
722 }
723}
724function canSign(input) {
725 return (
726 input.signScript !== undefined &&
727 input.signType !== undefined &&
728 input.pubkeys !== undefined &&
729 input.signatures !== undefined &&
730 input.signatures.length === input.pubkeys.length &&
731 input.pubkeys.length > 0 &&
732 (input.hasWitness === false || input.value !== undefined)
733 );
734}
735function signatureHashType(buffer) {
736 return buffer.readUInt8(buffer.length - 1);
737}
738function checkSignArgs(inputs, signParams) {
739 if (!PREVOUT_TYPES.has(signParams.prevOutScriptType)) {
740 throw new TypeError(
741 `Unknown prevOutScriptType "${signParams.prevOutScriptType}"`,
742 );
743 }
744 tfMessage(
745 typeforce.Number,
746 signParams.vin,
747 `sign must include vin parameter as Number (input index)`,
748 );
749 tfMessage(
750 types.Signer,
751 signParams.keyPair,
752 `sign must include keyPair parameter as Signer interface`,
753 );
754 tfMessage(
755 typeforce.maybe(typeforce.Number),
756 signParams.hashType,
757 `sign hashType parameter must be a number`,
758 );
759 const prevOutType = (inputs[signParams.vin] || []).prevOutType;
760 const posType = signParams.prevOutScriptType;
761 switch (posType) {
762 case 'p2pkh':
763 if (prevOutType && prevOutType !== 'pubkeyhash') {
764 throw new TypeError(
765 `input #${signParams.vin} is not of type p2pkh: ${prevOutType}`,
766 );
767 }
768 tfMessage(
769 typeforce.value(undefined),
770 signParams.witnessScript,
771 `${posType} requires NO witnessScript`,
772 );
773 tfMessage(
774 typeforce.value(undefined),
775 signParams.redeemScript,
776 `${posType} requires NO redeemScript`,
777 );
778 tfMessage(
779 typeforce.value(undefined),
780 signParams.witnessValue,
781 `${posType} requires NO witnessValue`,
782 );
783 break;
784 case 'p2pk':
785 if (prevOutType && prevOutType !== 'pubkey') {
786 throw new TypeError(
787 `input #${signParams.vin} is not of type p2pk: ${prevOutType}`,
788 );
789 }
790 tfMessage(
791 typeforce.value(undefined),
792 signParams.witnessScript,
793 `${posType} requires NO witnessScript`,
794 );
795 tfMessage(
796 typeforce.value(undefined),
797 signParams.redeemScript,
798 `${posType} requires NO redeemScript`,
799 );
800 tfMessage(
801 typeforce.value(undefined),
802 signParams.witnessValue,
803 `${posType} requires NO witnessValue`,
804 );
805 break;
806 case 'p2wpkh':
807 if (prevOutType && prevOutType !== 'witnesspubkeyhash') {
808 throw new TypeError(
809 `input #${signParams.vin} is not of type p2wpkh: ${prevOutType}`,
810 );
811 }
812 tfMessage(
813 typeforce.value(undefined),
814 signParams.witnessScript,
815 `${posType} requires NO witnessScript`,
816 );
817 tfMessage(
818 typeforce.value(undefined),
819 signParams.redeemScript,
820 `${posType} requires NO redeemScript`,
821 );
822 tfMessage(
823 types.Satoshi,
824 signParams.witnessValue,
825 `${posType} requires witnessValue`,
826 );
827 break;
828 case 'p2ms':
829 if (prevOutType && prevOutType !== 'multisig') {
830 throw new TypeError(
831 `input #${signParams.vin} is not of type p2ms: ${prevOutType}`,
832 );
833 }
834 tfMessage(
835 typeforce.value(undefined),
836 signParams.witnessScript,
837 `${posType} requires NO witnessScript`,
838 );
839 tfMessage(
840 typeforce.value(undefined),
841 signParams.redeemScript,
842 `${posType} requires NO redeemScript`,
843 );
844 tfMessage(
845 typeforce.value(undefined),
846 signParams.witnessValue,
847 `${posType} requires NO witnessValue`,
848 );
849 break;
850 case 'p2sh-p2wpkh':
851 if (prevOutType && prevOutType !== 'scripthash') {
852 throw new TypeError(
853 `input #${signParams.vin} is not of type p2sh-p2wpkh: ${prevOutType}`,
854 );
855 }
856 tfMessage(
857 typeforce.value(undefined),
858 signParams.witnessScript,
859 `${posType} requires NO witnessScript`,
860 );
861 tfMessage(
862 typeforce.Buffer,
863 signParams.redeemScript,
864 `${posType} requires redeemScript`,
865 );
866 tfMessage(
867 types.Satoshi,
868 signParams.witnessValue,
869 `${posType} requires witnessValue`,
870 );
871 break;
872 case 'p2sh-p2ms':
873 case 'p2sh-p2pk':
874 case 'p2sh-p2pkh':
875 if (prevOutType && prevOutType !== 'scripthash') {
876 throw new TypeError(
877 `input #${signParams.vin} is not of type ${posType}: ${prevOutType}`,
878 );
879 }
880 tfMessage(
881 typeforce.value(undefined),
882 signParams.witnessScript,
883 `${posType} requires NO witnessScript`,
884 );
885 tfMessage(
886 typeforce.Buffer,
887 signParams.redeemScript,
888 `${posType} requires redeemScript`,
889 );
890 tfMessage(
891 typeforce.value(undefined),
892 signParams.witnessValue,
893 `${posType} requires NO witnessValue`,
894 );
895 break;
896 case 'p2wsh-p2ms':
897 case 'p2wsh-p2pk':
898 case 'p2wsh-p2pkh':
899 if (prevOutType && prevOutType !== 'witnessscripthash') {
900 throw new TypeError(
901 `input #${signParams.vin} is not of type ${posType}: ${prevOutType}`,
902 );
903 }
904 tfMessage(
905 typeforce.Buffer,
906 signParams.witnessScript,
907 `${posType} requires witnessScript`,
908 );
909 tfMessage(
910 typeforce.value(undefined),
911 signParams.redeemScript,
912 `${posType} requires NO redeemScript`,
913 );
914 tfMessage(
915 types.Satoshi,
916 signParams.witnessValue,
917 `${posType} requires witnessValue`,
918 );
919 break;
920 case 'p2sh-p2wsh-p2ms':
921 case 'p2sh-p2wsh-p2pk':
922 case 'p2sh-p2wsh-p2pkh':
923 if (prevOutType && prevOutType !== 'scripthash') {
924 throw new TypeError(
925 `input #${signParams.vin} is not of type ${posType}: ${prevOutType}`,
926 );
927 }
928 tfMessage(
929 typeforce.Buffer,
930 signParams.witnessScript,
931 `${posType} requires witnessScript`,
932 );
933 tfMessage(
934 typeforce.Buffer,
935 signParams.redeemScript,
936 `${posType} requires witnessScript`,
937 );
938 tfMessage(
939 types.Satoshi,
940 signParams.witnessValue,
941 `${posType} requires witnessScript`,
942 );
943 break;
944 }
945}
946function trySign({
947 input,
948 ourPubKey,
949 keyPair,
950 signatureHash,
951 hashType,
952 useLowR,
953}) {
954 // enforce in order signing of public keys
955 let signed = false;
956 for (const [i, pubKey] of input.pubkeys.entries()) {
957 if (!ourPubKey.equals(pubKey)) continue;
958 if (input.signatures[i]) throw new Error('Signature already exists');
959 // TODO: add tests
960 if (ourPubKey.length !== 33 && input.hasWitness) {
961 throw new Error(
962 'BIP143 rejects uncompressed public keys in P2WPKH or P2WSH',
963 );
964 }
965 const signature = keyPair.sign(signatureHash, useLowR);
966 input.signatures[i] = bscript.signature.encode(signature, hashType);
967 signed = true;
968 }
969 if (!signed) throw new Error('Key pair cannot sign for this input');
970}
971function getSigningData(
972 network,
973 inputs,
974 needsOutputs,
975 tx,
976 signParams,
977 keyPair,
978 redeemScript,
979 hashType,
980 witnessValue,
981 witnessScript,
982 useLowR,
983) {
984 let vin;
985 if (typeof signParams === 'number') {
986 console.warn(
987 'DEPRECATED: TransactionBuilder sign method arguments ' +
988 'will change in v6, please use the TxbSignArg interface',
989 );
990 vin = signParams;
991 } else if (typeof signParams === 'object') {
992 checkSignArgs(inputs, signParams);
993 ({
994 vin,
995 keyPair,
996 redeemScript,
997 hashType,
998 witnessValue,
999 witnessScript,
1000 } = signParams);
1001 } else {
1002 throw new TypeError(
1003 'TransactionBuilder sign first arg must be TxbSignArg or number',
1004 );
1005 }
1006 if (keyPair === undefined) {
1007 throw new Error('sign requires keypair');
1008 }
1009 // TODO: remove keyPair.network matching in 4.0.0
1010 if (keyPair.network && keyPair.network !== network)
1011 throw new TypeError('Inconsistent network');
1012 if (!inputs[vin]) throw new Error('No input at index: ' + vin);
1013 hashType = hashType || transaction_1.Transaction.SIGHASH_ALL;
1014 if (needsOutputs(hashType)) throw new Error('Transaction needs outputs');
1015 const input = inputs[vin];
1016 // if redeemScript was previously provided, enforce consistency
1017 if (
1018 input.redeemScript !== undefined &&
1019 redeemScript &&
1020 !input.redeemScript.equals(redeemScript)
1021 ) {
1022 throw new Error('Inconsistent redeemScript');
1023 }
1024 const ourPubKey =
1025 keyPair.publicKey || (keyPair.getPublicKey && keyPair.getPublicKey());
1026 if (!canSign(input)) {
1027 if (witnessValue !== undefined) {
1028 if (input.value !== undefined && input.value !== witnessValue)
1029 throw new Error('Input did not match witnessValue');
1030 typeforce(types.Satoshi, witnessValue);
1031 input.value = witnessValue;
1032 }
1033 if (!canSign(input)) {
1034 const prepared = prepareInput(
1035 input,
1036 ourPubKey,
1037 redeemScript,
1038 witnessScript,
1039 );
1040 // updates inline
1041 Object.assign(input, prepared);
1042 }
1043 if (!canSign(input)) throw Error(input.prevOutType + ' not supported');
1044 }
1045 // ready to sign
1046 let signatureHash;
1047 if (input.hasWitness) {
1048 signatureHash = tx.hashForWitnessV0(
1049 vin,
1050 input.signScript,
1051 input.value,
1052 hashType,
1053 );
1054 } else {
1055 signatureHash = tx.hashForSignature(vin, input.signScript, hashType);
1056 }
1057 return {
1058 input,
1059 ourPubKey,
1060 keyPair,
1061 signatureHash,
1062 hashType,
1063 useLowR: !!useLowR,
1064 };
1065}