|
|
@ -1,24 +1,25 @@ |
|
|
|
import { Network } from './networks'; |
|
|
|
import * as networks from './networks'; |
|
|
|
import * as baddress from './address'; |
|
|
|
import { reverseBuffer } from './bufferutils'; |
|
|
|
import { Transaction, Output } from './transaction'; |
|
|
|
import * as classify from './classify'; |
|
|
|
import * as bcrypto from './crypto'; |
|
|
|
import { ECPairInterface } from './ecpair'; |
|
|
|
import * as ECPair from './ecpair'; |
|
|
|
import * as types from './types'; |
|
|
|
import * as baddress from './address'; |
|
|
|
import * as bcrypto from './crypto'; |
|
|
|
import * as bscript from './script'; |
|
|
|
import { Network } from './networks'; |
|
|
|
import * as networks from './networks'; |
|
|
|
import { Payment } from './payments'; |
|
|
|
import * as payments from './payments'; |
|
|
|
import * as classify from './classify'; |
|
|
|
import * as bscript from './script'; |
|
|
|
import { OPS as ops } from './script'; |
|
|
|
import { Output, Transaction } from './transaction'; |
|
|
|
import * as types from './types'; |
|
|
|
const typeforce = require('typeforce'); |
|
|
|
|
|
|
|
const SCRIPT_TYPES = classify.types; |
|
|
|
|
|
|
|
type TxbSignatures = Array<Buffer> | Array<Buffer | undefined>; |
|
|
|
type TxbPubkeys = Array<Buffer | undefined>; |
|
|
|
type TxbWitness = Array<Buffer>; |
|
|
|
type MaybeBuffer = Buffer | undefined; |
|
|
|
type TxbSignatures = Buffer[] | MaybeBuffer[]; |
|
|
|
type TxbPubkeys = MaybeBuffer[]; |
|
|
|
type TxbWitness = Buffer[]; |
|
|
|
type TxbScriptType = string; |
|
|
|
type TxbScript = Buffer; |
|
|
|
|
|
|
@ -58,24 +59,6 @@ function txIsTransaction(tx: Buffer | string | Transaction): tx is Transaction { |
|
|
|
} |
|
|
|
|
|
|
|
export class TransactionBuilder { |
|
|
|
network: Network; |
|
|
|
maximumFeeRate: number; |
|
|
|
private __prevTxSet: { [index: string]: boolean }; |
|
|
|
private __inputs: Array<TxbInput>; |
|
|
|
private __tx: Transaction; |
|
|
|
|
|
|
|
constructor(network?: Network, maximumFeeRate?: number) { |
|
|
|
this.__prevTxSet = {}; |
|
|
|
this.network = network || networks.bitcoin; |
|
|
|
|
|
|
|
// WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth)
|
|
|
|
this.maximumFeeRate = maximumFeeRate || 2500; |
|
|
|
|
|
|
|
this.__inputs = []; |
|
|
|
this.__tx = new Transaction(); |
|
|
|
this.__tx.version = 2; |
|
|
|
} |
|
|
|
|
|
|
|
static fromTransaction( |
|
|
|
transaction: Transaction, |
|
|
|
network?: Network, |
|
|
@ -88,7 +71,7 @@ export class TransactionBuilder { |
|
|
|
|
|
|
|
// Copy outputs (done first to avoid signature invalidation)
|
|
|
|
transaction.outs.forEach(txOut => { |
|
|
|
txb.addOutput(txOut.script, (<Output>txOut).value); |
|
|
|
txb.addOutput(txOut.script, (txOut as Output).value); |
|
|
|
}); |
|
|
|
|
|
|
|
// Copy inputs
|
|
|
@ -101,19 +84,37 @@ export class TransactionBuilder { |
|
|
|
}); |
|
|
|
|
|
|
|
// fix some things not possible through the public API
|
|
|
|
txb.__inputs.forEach((input, i) => { |
|
|
|
txb.__INPUTS.forEach((input, i) => { |
|
|
|
fixMultisigOrder(input, transaction, i); |
|
|
|
}); |
|
|
|
|
|
|
|
return txb; |
|
|
|
} |
|
|
|
|
|
|
|
network: Network; |
|
|
|
maximumFeeRate: number; |
|
|
|
private __PREV_TX_SET: { [index: string]: boolean }; |
|
|
|
private __INPUTS: TxbInput[]; |
|
|
|
private __TX: Transaction; |
|
|
|
|
|
|
|
constructor(network?: Network, maximumFeeRate?: number) { |
|
|
|
this.__PREV_TX_SET = {}; |
|
|
|
this.network = network || networks.bitcoin; |
|
|
|
|
|
|
|
// WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth)
|
|
|
|
this.maximumFeeRate = maximumFeeRate || 2500; |
|
|
|
|
|
|
|
this.__INPUTS = []; |
|
|
|
this.__TX = new Transaction(); |
|
|
|
this.__TX.version = 2; |
|
|
|
} |
|
|
|
|
|
|
|
setLockTime(locktime: number): void { |
|
|
|
typeforce(types.UInt32, locktime); |
|
|
|
|
|
|
|
// if any signatures exist, throw
|
|
|
|
if ( |
|
|
|
this.__inputs.some(input => { |
|
|
|
this.__INPUTS.some(input => { |
|
|
|
if (!input.signatures) return false; |
|
|
|
|
|
|
|
return input.signatures.some(s => s !== undefined); |
|
|
@ -122,14 +123,14 @@ export class TransactionBuilder { |
|
|
|
throw new Error('No, this would invalidate signatures'); |
|
|
|
} |
|
|
|
|
|
|
|
this.__tx.locktime = locktime; |
|
|
|
this.__TX.locktime = locktime; |
|
|
|
} |
|
|
|
|
|
|
|
setVersion(version: number): void { |
|
|
|
typeforce(types.UInt32, version); |
|
|
|
|
|
|
|
// XXX: this might eventually become more complex depending on what the versions represent
|
|
|
|
this.__tx.version = version; |
|
|
|
this.__TX.version = version; |
|
|
|
} |
|
|
|
|
|
|
|
addInput( |
|
|
@ -142,7 +143,7 @@ export class TransactionBuilder { |
|
|
|
throw new Error('No, this would invalidate signatures'); |
|
|
|
} |
|
|
|
|
|
|
|
let value: number | undefined = undefined; |
|
|
|
let value: number | undefined; |
|
|
|
|
|
|
|
// is it a hex string?
|
|
|
|
if (txIsString(txHash)) { |
|
|
@ -153,72 +154,18 @@ export class TransactionBuilder { |
|
|
|
} else if (txIsTransaction(txHash)) { |
|
|
|
const txOut = txHash.outs[vout]; |
|
|
|
prevOutScript = txOut.script; |
|
|
|
value = (<Output>txOut).value; |
|
|
|
value = (txOut as Output).value; |
|
|
|
|
|
|
|
txHash = <Buffer>txHash.getHash(false); |
|
|
|
txHash = txHash.getHash(false) as Buffer; |
|
|
|
} |
|
|
|
|
|
|
|
return this.__addInputUnsafe(txHash, vout, { |
|
|
|
sequence: sequence, |
|
|
|
prevOutScript: prevOutScript, |
|
|
|
value: value, |
|
|
|
sequence, |
|
|
|
prevOutScript, |
|
|
|
value, |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private __addInputUnsafe( |
|
|
|
txHash: Buffer, |
|
|
|
vout: number, |
|
|
|
options: TxbInput, |
|
|
|
): number { |
|
|
|
if (Transaction.isCoinbaseHash(txHash)) { |
|
|
|
throw new Error('coinbase inputs not supported'); |
|
|
|
} |
|
|
|
|
|
|
|
const prevTxOut = txHash.toString('hex') + ':' + vout; |
|
|
|
if (this.__prevTxSet[prevTxOut] !== undefined) |
|
|
|
throw new Error('Duplicate TxOut: ' + prevTxOut); |
|
|
|
|
|
|
|
let input = <TxbInput>{}; |
|
|
|
|
|
|
|
// derive what we can from the scriptSig
|
|
|
|
if (options.script !== undefined) { |
|
|
|
input = expandInput(options.script, options.witness || []); |
|
|
|
} |
|
|
|
|
|
|
|
// if an input value was given, retain it
|
|
|
|
if (options.value !== undefined) { |
|
|
|
input.value = options.value; |
|
|
|
} |
|
|
|
|
|
|
|
// derive what we can from the previous transactions output script
|
|
|
|
if (!input.prevOutScript && options.prevOutScript) { |
|
|
|
let prevOutType; |
|
|
|
|
|
|
|
if (!input.pubkeys && !input.signatures) { |
|
|
|
const expanded = expandOutput(options.prevOutScript); |
|
|
|
if (expanded.pubkeys) { |
|
|
|
input.pubkeys = expanded.pubkeys; |
|
|
|
input.signatures = expanded.signatures; |
|
|
|
} |
|
|
|
|
|
|
|
prevOutType = expanded.type; |
|
|
|
} |
|
|
|
|
|
|
|
input.prevOutScript = options.prevOutScript; |
|
|
|
input.prevOutType = prevOutType || classify.output(options.prevOutScript); |
|
|
|
} |
|
|
|
|
|
|
|
const vin = this.__tx.addInput( |
|
|
|
txHash, |
|
|
|
vout, |
|
|
|
options.sequence, |
|
|
|
options.scriptSig, |
|
|
|
); |
|
|
|
this.__inputs[vin] = input; |
|
|
|
this.__prevTxSet[prevTxOut] = true; |
|
|
|
return vin; |
|
|
|
} |
|
|
|
|
|
|
|
addOutput(scriptPubKey: string | Buffer, value: number): number { |
|
|
|
if (!this.__canModifyOutputs()) { |
|
|
|
throw new Error('No, this would invalidate signatures'); |
|
|
@ -229,7 +176,7 @@ export class TransactionBuilder { |
|
|
|
scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network); |
|
|
|
} |
|
|
|
|
|
|
|
return this.__tx.addOutput(scriptPubKey, value); |
|
|
|
return this.__TX.addOutput(scriptPubKey, value); |
|
|
|
} |
|
|
|
|
|
|
|
build(): Transaction { |
|
|
@ -240,41 +187,6 @@ export class TransactionBuilder { |
|
|
|
return this.__build(true); |
|
|
|
} |
|
|
|
|
|
|
|
private __build(allowIncomplete?: boolean): Transaction { |
|
|
|
if (!allowIncomplete) { |
|
|
|
if (!this.__tx.ins.length) throw new Error('Transaction has no inputs'); |
|
|
|
if (!this.__tx.outs.length) throw new Error('Transaction has no outputs'); |
|
|
|
} |
|
|
|
|
|
|
|
const tx = this.__tx.clone(); |
|
|
|
|
|
|
|
// create script signatures from inputs
|
|
|
|
this.__inputs.forEach((input, i) => { |
|
|
|
if (!input.prevOutType && !allowIncomplete) |
|
|
|
throw new Error('Transaction is not complete'); |
|
|
|
|
|
|
|
const result = build(input.prevOutType!, input, allowIncomplete); |
|
|
|
if (!result) { |
|
|
|
if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) |
|
|
|
throw new Error('Unknown input type'); |
|
|
|
if (!allowIncomplete) throw new Error('Not enough information'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
tx.setInputScript(i, result.input!); |
|
|
|
tx.setWitness(i, result.witness!); |
|
|
|
}); |
|
|
|
|
|
|
|
if (!allowIncomplete) { |
|
|
|
// do not rely on this, its merely a last resort
|
|
|
|
if (this.__overMaximumFees(tx.virtualSize())) { |
|
|
|
throw new Error('Transaction has absurd fees'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return tx; |
|
|
|
} |
|
|
|
|
|
|
|
sign( |
|
|
|
vin: number, |
|
|
|
keyPair: ECPairInterface, |
|
|
@ -286,13 +198,13 @@ export class TransactionBuilder { |
|
|
|
// TODO: remove keyPair.network matching in 4.0.0
|
|
|
|
if (keyPair.network && keyPair.network !== this.network) |
|
|
|
throw new TypeError('Inconsistent network'); |
|
|
|
if (!this.__inputs[vin]) throw new Error('No input at index: ' + vin); |
|
|
|
if (!this.__INPUTS[vin]) throw new Error('No input at index: ' + vin); |
|
|
|
|
|
|
|
hashType = hashType || Transaction.SIGHASH_ALL; |
|
|
|
if (this.__needsOutputs(hashType)) |
|
|
|
throw new Error('Transaction needs outputs'); |
|
|
|
|
|
|
|
const input = this.__inputs[vin]; |
|
|
|
const input = this.__INPUTS[vin]; |
|
|
|
|
|
|
|
// if redeemScript was previously provided, enforce consistency
|
|
|
|
if ( |
|
|
@ -307,7 +219,7 @@ export class TransactionBuilder { |
|
|
|
if (!canSign(input)) { |
|
|
|
if (witnessValue !== undefined) { |
|
|
|
if (input.value !== undefined && input.value !== witnessValue) |
|
|
|
throw new Error("Input didn't match witnessValue"); |
|
|
|
throw new Error('Input did not match witnessValue'); |
|
|
|
typeforce(types.Satoshi, witnessValue); |
|
|
|
input.value = witnessValue; |
|
|
|
} |
|
|
@ -330,16 +242,16 @@ export class TransactionBuilder { |
|
|
|
// ready to sign
|
|
|
|
let signatureHash: Buffer; |
|
|
|
if (input.hasWitness) { |
|
|
|
signatureHash = this.__tx.hashForWitnessV0( |
|
|
|
signatureHash = this.__TX.hashForWitnessV0( |
|
|
|
vin, |
|
|
|
<Buffer>input.signScript, |
|
|
|
<number>input.value, |
|
|
|
input.signScript as Buffer, |
|
|
|
input.value as number, |
|
|
|
hashType, |
|
|
|
); |
|
|
|
} else { |
|
|
|
signatureHash = this.__tx.hashForSignature( |
|
|
|
signatureHash = this.__TX.hashForSignature( |
|
|
|
vin, |
|
|
|
<Buffer>input.signScript, |
|
|
|
input.signScript as Buffer, |
|
|
|
hashType, |
|
|
|
); |
|
|
|
} |
|
|
@ -364,8 +276,97 @@ export class TransactionBuilder { |
|
|
|
if (!signed) throw new Error('Key pair cannot sign for this input'); |
|
|
|
} |
|
|
|
|
|
|
|
private __addInputUnsafe( |
|
|
|
txHash: Buffer, |
|
|
|
vout: number, |
|
|
|
options: TxbInput, |
|
|
|
): number { |
|
|
|
if (Transaction.isCoinbaseHash(txHash)) { |
|
|
|
throw new Error('coinbase inputs not supported'); |
|
|
|
} |
|
|
|
|
|
|
|
const prevTxOut = txHash.toString('hex') + ':' + vout; |
|
|
|
if (this.__PREV_TX_SET[prevTxOut] !== undefined) |
|
|
|
throw new Error('Duplicate TxOut: ' + prevTxOut); |
|
|
|
|
|
|
|
let input: TxbInput = {}; |
|
|
|
|
|
|
|
// derive what we can from the scriptSig
|
|
|
|
if (options.script !== undefined) { |
|
|
|
input = expandInput(options.script, options.witness || []); |
|
|
|
} |
|
|
|
|
|
|
|
// if an input value was given, retain it
|
|
|
|
if (options.value !== undefined) { |
|
|
|
input.value = options.value; |
|
|
|
} |
|
|
|
|
|
|
|
// derive what we can from the previous transactions output script
|
|
|
|
if (!input.prevOutScript && options.prevOutScript) { |
|
|
|
let prevOutType; |
|
|
|
|
|
|
|
if (!input.pubkeys && !input.signatures) { |
|
|
|
const expanded = expandOutput(options.prevOutScript); |
|
|
|
if (expanded.pubkeys) { |
|
|
|
input.pubkeys = expanded.pubkeys; |
|
|
|
input.signatures = expanded.signatures; |
|
|
|
} |
|
|
|
|
|
|
|
prevOutType = expanded.type; |
|
|
|
} |
|
|
|
|
|
|
|
input.prevOutScript = options.prevOutScript; |
|
|
|
input.prevOutType = prevOutType || classify.output(options.prevOutScript); |
|
|
|
} |
|
|
|
|
|
|
|
const vin = this.__TX.addInput( |
|
|
|
txHash, |
|
|
|
vout, |
|
|
|
options.sequence, |
|
|
|
options.scriptSig, |
|
|
|
); |
|
|
|
this.__INPUTS[vin] = input; |
|
|
|
this.__PREV_TX_SET[prevTxOut] = true; |
|
|
|
return vin; |
|
|
|
} |
|
|
|
|
|
|
|
private __build(allowIncomplete?: boolean): Transaction { |
|
|
|
if (!allowIncomplete) { |
|
|
|
if (!this.__TX.ins.length) throw new Error('Transaction has no inputs'); |
|
|
|
if (!this.__TX.outs.length) throw new Error('Transaction has no outputs'); |
|
|
|
} |
|
|
|
|
|
|
|
const tx = this.__TX.clone(); |
|
|
|
|
|
|
|
// create script signatures from inputs
|
|
|
|
this.__INPUTS.forEach((input, i) => { |
|
|
|
if (!input.prevOutType && !allowIncomplete) |
|
|
|
throw new Error('Transaction is not complete'); |
|
|
|
|
|
|
|
const result = build(input.prevOutType!, input, allowIncomplete); |
|
|
|
if (!result) { |
|
|
|
if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) |
|
|
|
throw new Error('Unknown input type'); |
|
|
|
if (!allowIncomplete) throw new Error('Not enough information'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
tx.setInputScript(i, result.input!); |
|
|
|
tx.setWitness(i, result.witness!); |
|
|
|
}); |
|
|
|
|
|
|
|
if (!allowIncomplete) { |
|
|
|
// do not rely on this, its merely a last resort
|
|
|
|
if (this.__overMaximumFees(tx.virtualSize())) { |
|
|
|
throw new Error('Transaction has absurd fees'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return tx; |
|
|
|
} |
|
|
|
|
|
|
|
private __canModifyInputs(): boolean { |
|
|
|
return this.__inputs.every(input => { |
|
|
|
return this.__INPUTS.every(input => { |
|
|
|
if (!input.signatures) return true; |
|
|
|
|
|
|
|
return input.signatures.every(signature => { |
|
|
@ -381,14 +382,14 @@ export class TransactionBuilder { |
|
|
|
|
|
|
|
private __needsOutputs(signingHashType: number): boolean { |
|
|
|
if (signingHashType === Transaction.SIGHASH_ALL) { |
|
|
|
return this.__tx.outs.length === 0; |
|
|
|
return this.__TX.outs.length === 0; |
|
|
|
} |
|
|
|
|
|
|
|
// if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs
|
|
|
|
// .build() will fail, but .buildIncomplete() is OK
|
|
|
|
return ( |
|
|
|
this.__tx.outs.length === 0 && |
|
|
|
this.__inputs.some(input => { |
|
|
|
this.__TX.outs.length === 0 && |
|
|
|
this.__INPUTS.some(input => { |
|
|
|
if (!input.signatures) return false; |
|
|
|
|
|
|
|
return input.signatures.some(signature => { |
|
|
@ -402,10 +403,10 @@ export class TransactionBuilder { |
|
|
|
} |
|
|
|
|
|
|
|
private __canModifyOutputs(): boolean { |
|
|
|
const nInputs = this.__tx.ins.length; |
|
|
|
const nOutputs = this.__tx.outs.length; |
|
|
|
const nInputs = this.__TX.ins.length; |
|
|
|
const nOutputs = this.__TX.outs.length; |
|
|
|
|
|
|
|
return this.__inputs.every(input => { |
|
|
|
return this.__INPUTS.every(input => { |
|
|
|
if (input.signatures === undefined) return true; |
|
|
|
|
|
|
|
return input.signatures.every(signature => { |
|
|
@ -427,11 +428,14 @@ export class TransactionBuilder { |
|
|
|
|
|
|
|
private __overMaximumFees(bytes: number): boolean { |
|
|
|
// not all inputs will have .value defined
|
|
|
|
const incoming = this.__inputs.reduce((a, x) => a + (x.value! >>> 0), 0); |
|
|
|
const incoming = this.__INPUTS.reduce((a, x) => a + (x.value! >>> 0), 0); |
|
|
|
|
|
|
|
// but all outputs do, and if we have any input value
|
|
|
|
// we can immediately determine if the outputs are too small
|
|
|
|
const outgoing = this.__tx.outs.reduce((a, x) => a + (<Output>x).value, 0); |
|
|
|
const outgoing = this.__TX.outs.reduce( |
|
|
|
(a, x) => a + (x as Output).value, |
|
|
|
0, |
|
|
|
); |
|
|
|
const fee = incoming - outgoing; |
|
|
|
const feeRate = fee / bytes; |
|
|
|
|
|
|
@ -441,7 +445,7 @@ export class TransactionBuilder { |
|
|
|
|
|
|
|
function expandInput( |
|
|
|
scriptSig: Buffer, |
|
|
|
witnessStack: Array<Buffer>, |
|
|
|
witnessStack: Buffer[], |
|
|
|
type?: string, |
|
|
|
scriptPubKey?: Buffer, |
|
|
|
): TxbInput { |
|
|
@ -502,8 +506,8 @@ function expandInput( |
|
|
|
|
|
|
|
return { |
|
|
|
prevOutType: SCRIPT_TYPES.P2MS, |
|
|
|
pubkeys: pubkeys, |
|
|
|
signatures: signatures, |
|
|
|
pubkeys, |
|
|
|
signatures, |
|
|
|
maxSignatures: m, |
|
|
|
}; |
|
|
|
} |
|
|
@ -681,12 +685,12 @@ function prepareInput( |
|
|
|
witnessScript: Buffer, |
|
|
|
): TxbInput { |
|
|
|
if (redeemScript && witnessScript) { |
|
|
|
const p2wsh = <Payment>( |
|
|
|
payments.p2wsh({ redeem: { output: witnessScript } }) |
|
|
|
); |
|
|
|
const p2wshAlt = <Payment>payments.p2wsh({ output: redeemScript }); |
|
|
|
const p2sh = <Payment>payments.p2sh({ redeem: { output: redeemScript } }); |
|
|
|
const p2shAlt = <Payment>payments.p2sh({ redeem: p2wsh }); |
|
|
|
const p2wsh = payments.p2wsh({ |
|
|
|
redeem: { output: witnessScript }, |
|
|
|
}) as Payment; |
|
|
|
const p2wshAlt = payments.p2wsh({ output: redeemScript }) as Payment; |
|
|
|
const p2sh = payments.p2sh({ redeem: { output: redeemScript } }) as Payment; |
|
|
|
const p2shAlt = payments.p2sh({ redeem: p2wsh }) as Payment; |
|
|
|
|
|
|
|
// enforces P2SH(P2WSH(...))
|
|
|
|
if (!p2wsh.hash!.equals(p2wshAlt.hash!)) |
|
|
@ -706,7 +710,7 @@ function prepareInput( |
|
|
|
expanded.signatures = input.signatures; |
|
|
|
} |
|
|
|
|
|
|
|
let signScript = witnessScript; |
|
|
|
const signScript = witnessScript; |
|
|
|
if (expanded.type === SCRIPT_TYPES.P2WPKH) |
|
|
|
throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure'); |
|
|
|
|
|
|
@ -731,12 +735,12 @@ function prepareInput( |
|
|
|
} |
|
|
|
|
|
|
|
if (redeemScript) { |
|
|
|
const p2sh = <Payment>payments.p2sh({ redeem: { output: redeemScript } }); |
|
|
|
const p2sh = payments.p2sh({ redeem: { output: redeemScript } }) as Payment; |
|
|
|
|
|
|
|
if (input.prevOutScript) { |
|
|
|
let p2shAlt; |
|
|
|
try { |
|
|
|
p2shAlt = <Payment>payments.p2sh({ output: input.prevOutScript }); |
|
|
|
p2shAlt = payments.p2sh({ output: input.prevOutScript }) as Payment; |
|
|
|
} catch (e) { |
|
|
|
throw new Error('PrevOutScript must be P2SH'); |
|
|
|
} |
|
|
@ -799,7 +803,7 @@ function prepareInput( |
|
|
|
expanded.signatures = input.signatures; |
|
|
|
} |
|
|
|
|
|
|
|
let signScript = witnessScript; |
|
|
|
const signScript = witnessScript; |
|
|
|
if (expanded.type === SCRIPT_TYPES.P2WPKH) |
|
|
|
throw new Error('P2WSH(P2WPKH) is a consensus failure'); |
|
|
|
|
|
|
@ -846,9 +850,8 @@ function prepareInput( |
|
|
|
|
|
|
|
let signScript = input.prevOutScript; |
|
|
|
if (expanded.type === SCRIPT_TYPES.P2WPKH) { |
|
|
|
signScript = <Buffer>( |
|
|
|
payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output |
|
|
|
); |
|
|
|
signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }) |
|
|
|
.output as Buffer; |
|
|
|
} |
|
|
|
|
|
|
|
return { |
|
|
@ -868,7 +871,7 @@ function prepareInput( |
|
|
|
const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output; |
|
|
|
return { |
|
|
|
prevOutType: SCRIPT_TYPES.P2PKH, |
|
|
|
prevOutScript: prevOutScript, |
|
|
|
prevOutScript, |
|
|
|
|
|
|
|
hasWitness: false, |
|
|
|
signScript: prevOutScript, |
|
|
@ -884,8 +887,8 @@ function build( |
|
|
|
input: TxbInput, |
|
|
|
allowIncomplete?: boolean, |
|
|
|
): Payment | undefined { |
|
|
|
const pubkeys = <Array<Buffer>>(input.pubkeys || []); |
|
|
|
let signatures = <Array<Buffer>>(input.signatures || []); |
|
|
|
const pubkeys = (input.pubkeys || []) as Buffer[]; |
|
|
|
let signatures = (input.signatures || []) as Buffer[]; |
|
|
|
|
|
|
|
switch (type) { |
|
|
|
case SCRIPT_TYPES.P2PKH: { |
|
|
|