From 01c7ac39b611e63cfff38d5292b295fe15e65dd3 Mon Sep 17 00:00:00 2001 From: junderw Date: Tue, 9 Jul 2019 18:03:15 +0900 Subject: [PATCH] Add clone, addInputs, addOutputs --- src/psbt.js | 14 ++ test/integration/transactions-psbt.js | 339 ++++++++++++++------------ ts_src/psbt.ts | 17 ++ types/psbt.d.ts | 3 + 4 files changed, 221 insertions(+), 152 deletions(-) diff --git a/src/psbt.js b/src/psbt.js index 58a56dd..33a32a3 100644 --- a/src/psbt.js +++ b/src/psbt.js @@ -95,6 +95,12 @@ class Psbt extends bip174_1.Psbt { get inputCount() { return this.inputs.length; } + clone() { + // TODO: more efficient cloning + const res = Psbt.fromBuffer(this.toBuffer()); + res.opts = JSON.parse(JSON.stringify(this.opts)); + return res; + } setMaximumFeeRate(satoshiPerByte) { check32Bit(satoshiPerByte); // 42.9 BTC per byte IS excessive... so throw this.opts.maximumFeeRate = satoshiPerByte; @@ -129,6 +135,10 @@ class Psbt extends bip174_1.Psbt { c.__EXTRACTED_TX = undefined; return this; } + addInputs(inputDatas) { + inputDatas.forEach(inputData => this.addInput(inputData)); + return this; + } addInput(inputData) { checkInputsForPartialSig(this.inputs, 'addInput'); const c = this.__CACHE; @@ -138,6 +148,10 @@ class Psbt extends bip174_1.Psbt { c.__EXTRACTED_TX = undefined; return this; } + addOutputs(outputDatas) { + outputDatas.forEach(outputData => this.addOutput(outputData)); + return this; + } addOutput(outputData) { checkInputsForPartialSig(this.inputs, 'addOutput'); const { address } = outputData; diff --git a/test/integration/transactions-psbt.js b/test/integration/transactions-psbt.js index a7398a8..96ae073 100644 --- a/test/integration/transactions-psbt.js +++ b/test/integration/transactions-psbt.js @@ -1,17 +1,19 @@ -const { describe, it } = require('mocha') -const assert = require('assert') -const bitcoin = require('../../') -const regtestUtils = require('./_regtest') -const regtest = regtestUtils.network +const { describe, it } = require('mocha'); +const assert = require('assert'); +const bitcoin = require('../../'); +const regtestUtils = require('./_regtest'); +const regtest = regtestUtils.network; // See bottom of file for some helper functions used to make the payment objects needed. describe('bitcoinjs-lib (transactions with psbt)', () => { it('can create a 1-to-1 Transaction', () => { - const alice = bitcoin.ECPair.fromWIF('L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr') - const psbt = new bitcoin.Psbt() - psbt.setVersion(2) // These are defaults. This line is not needed. - psbt.setLocktime(0) // These are defaults. This line is not needed. + const alice = bitcoin.ECPair.fromWIF( + 'L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr', + ); + const psbt = new bitcoin.Psbt(); + psbt.setVersion(2); // These are defaults. This line is not needed. + psbt.setLocktime(0); // These are defaults. This line is not needed. psbt.addInput({ // if hash is string, txid, if hash is Buffer, is reversed compared to txid hash: '7d067b4a697a09d2c3cff7d4d9506c9955e93bff41bf82d439da7d030382bc3e', @@ -21,18 +23,18 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { // non-segwit inputs now require passing the whole previous tx as Buffer nonWitnessUtxo: Buffer.from( '0200000001f9f34e95b9d5c8abcd20fc5bd4a825d1517be62f0f775e5f36da944d9' + - '452e550000000006b483045022100c86e9a111afc90f64b4904bd609e9eaed80d48' + - 'ca17c162b1aca0a788ac3526f002207bb79b60d4fc6526329bf18a77135dc566020' + - '9e761da46e1c2f1152ec013215801210211755115eabf846720f5cb18f248666fec' + - '631e5e1e66009ce3710ceea5b1ad13ffffffff01' + - // value in satoshis (Int64LE) = 0x015f90 = 90000 - '905f010000000000' + - // scriptPubkey length - '19' + - // scriptPubkey - '76a9148bbc95d2709c71607c60ee3f097c1217482f518d88ac' + - // locktime - '00000000', + '452e550000000006b483045022100c86e9a111afc90f64b4904bd609e9eaed80d48' + + 'ca17c162b1aca0a788ac3526f002207bb79b60d4fc6526329bf18a77135dc566020' + + '9e761da46e1c2f1152ec013215801210211755115eabf846720f5cb18f248666fec' + + '631e5e1e66009ce3710ceea5b1ad13ffffffff01' + + // value in satoshis (Int64LE) = 0x015f90 = 90000 + '905f010000000000' + + // scriptPubkey length + '19' + + // scriptPubkey + '76a9148bbc95d2709c71607c60ee3f097c1217482f518d88ac' + + // locktime + '00000000', 'hex', ), @@ -47,40 +49,50 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { // }, // Not featured here: redeemScript. A Buffer of the redeemScript - }) + }); psbt.addOutput({ address: '1KRMKfeZcmosxALVYESdPNez1AP1mEtywp', - value: 80000 - }) - psbt.signInput(0, alice) - psbt.validateSignatures(0) - psbt.finalizeAllInputs() + value: 80000, + }); + psbt.signInput(0, alice); + psbt.validateSignatures(0); + psbt.finalizeAllInputs(); assert.strictEqual( psbt.extractTransaction().toHex(), '02000000013ebc8203037dda39d482bf41ff3be955996c50d9d4f7cfc3d2097a694a7' + - 'b067d000000006b483045022100931b6db94aed25d5486884d83fc37160f37f3368c0' + - 'd7f48c757112abefec983802205fda64cff98c849577026eb2ce916a50ea70626a766' + - '9f8596dd89b720a26b4d501210365db9da3f8a260078a7e8f8b708a1161468fb2323f' + - 'fda5ec16b261ec1056f455ffffffff0180380100000000001976a914ca0d36044e0dc' + - '08a22724efa6f6a07b0ec4c79aa88ac00000000', - ) - }) + 'b067d000000006b483045022100931b6db94aed25d5486884d83fc37160f37f3368c0' + + 'd7f48c757112abefec983802205fda64cff98c849577026eb2ce916a50ea70626a766' + + '9f8596dd89b720a26b4d501210365db9da3f8a260078a7e8f8b708a1161468fb2323f' + + 'fda5ec16b261ec1056f455ffffffff0180380100000000001976a914ca0d36044e0dc' + + '08a22724efa6f6a07b0ec4c79aa88ac00000000', + ); + }); it('can create (and broadcast via 3PBP) a typical Transaction', async () => { // these are { payment: Payment; keys: ECPair[] } - const alice1 = createPayment('p2pkh') - const alice2 = createPayment('p2pkh') + const alice1 = createPayment('p2pkh'); + const alice2 = createPayment('p2pkh'); // give Alice 2 unspent outputs - const inputData1 = await getInputData(5e4, alice1.payment, false, 'noredeem') - const inputData2 = await getInputData(7e4, alice2.payment, false, 'noredeem') + const inputData1 = await getInputData( + 5e4, + alice1.payment, + false, + 'noredeem', + ); + const inputData2 = await getInputData( + 7e4, + alice2.payment, + false, + 'noredeem', + ); { const { hash, // string of txid or Buffer of tx hash. (txid and hash are reverse order) index, // the output index of the txo you are spending nonWitnessUtxo, // the full previous transaction as a Buffer - } = inputData1 - assert.deepStrictEqual({ hash, index, nonWitnessUtxo }, inputData1) + } = inputData1; + assert.deepStrictEqual({ hash, index, nonWitnessUtxo }, inputData1); } // network is only needed if you pass an address to addOutput @@ -90,12 +102,12 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData2) // alice2 unspent .addOutput({ address: 'mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf', - value: 8e4 + value: 8e4, }) // the actual "spend" .addOutput({ address: alice2.payment.address, // OR script, which is a Buffer. - value: 1e4 - }) // Alice's change + value: 1e4, + }); // Alice's change // (in)(5e4 + 7e4) - (out)(8e4 + 1e4) = (fee)3e4 = 30000, this is the miner fee // Let's show a new feature with PSBT. @@ -103,231 +115,248 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { // (this is not necessary, but a nice feature) // encode to send out to the signers - const psbtBaseText = psbt.toBase64() + const psbtBaseText = psbt.toBase64(); // each signer imports - const signer1 = bitcoin.Psbt.fromBase64(psbtBaseText) - const signer2 = bitcoin.Psbt.fromBase64(psbtBaseText) + const signer1 = bitcoin.Psbt.fromBase64(psbtBaseText); + const signer2 = bitcoin.Psbt.fromBase64(psbtBaseText); // Alice signs each input with the respective private keys // signInput and signInputAsync are better // (They take the input index explicitly as the first arg) - signer1.sign(alice1.keys[0]) - signer2.sign(alice2.keys[0]) + signer1.sign(alice1.keys[0]); + signer2.sign(alice2.keys[0]); // If your signer object's sign method returns a promise, use the following // await signer2.signAsync(alice2.keys[0]) // encode to send back to combiner (signer 1 and 2 are not near each other) - const s1text = signer1.toBase64() - const s2text = signer2.toBase64() + const s1text = signer1.toBase64(); + const s2text = signer2.toBase64(); - const final1 = bitcoin.Psbt.fromBase64(s1text) - const final2 = bitcoin.Psbt.fromBase64(s2text) + const final1 = bitcoin.Psbt.fromBase64(s1text); + const final2 = bitcoin.Psbt.fromBase64(s2text); // final1.combine(final2) would give the exact same result - psbt.combine(final1, final2) + psbt.combine(final1, final2); // Finalizer wants to check all signatures are valid before finalizing. // If the finalizer wants to check for specific pubkeys, the second arg // can be passed. See the first multisig example below. - assert.strictEqual(psbt.validateSignatures(0), true) - assert.strictEqual(psbt.validateSignatures(1), true) + assert.strictEqual(psbt.validateSignatures(0), true); + assert.strictEqual(psbt.validateSignatures(1), true); // This step it new. Since we separate the signing operation and // the creation of the scriptSig and witness stack, we are able to - psbt.finalizeAllInputs() + psbt.finalizeAllInputs(); // it returns an array of the success of each input, also a result attribute // which is true if all array items are true. // build and broadcast our RegTest network - await regtestUtils.broadcast(psbt.extractTransaction().toHex()) + await regtestUtils.broadcast(psbt.extractTransaction().toHex()); // to build and broadcast to the actual Bitcoin network, see https://github.com/bitcoinjs/bitcoinjs-lib/issues/839 - }) + }); it('can create (and broadcast via 3PBP) a Transaction with an OP_RETURN output', async () => { - const alice1 = createPayment('p2pkh') - const inputData1 = await getInputData(2e5, alice1.payment, false, 'noredeem') + const alice1 = createPayment('p2pkh'); + const inputData1 = await getInputData( + 2e5, + alice1.payment, + false, + 'noredeem', + ); - const data = Buffer.from('bitcoinjs-lib', 'utf8') - const embed = bitcoin.payments.embed({ data: [data] }) + const data = Buffer.from('bitcoinjs-lib', 'utf8'); + const embed = bitcoin.payments.embed({ data: [data] }); const psbt = new bitcoin.Psbt({ network: regtest }) .addInput(inputData1) .addOutput({ script: embed.output, - value: 1000 + value: 1000, }) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 1e5 + value: 1e5, }) - .signInput(0, alice1.keys[0]) + .signInput(0, alice1.keys[0]); - assert.strictEqual(psbt.validateSignatures(0), true) - psbt.finalizeAllInputs() + assert.strictEqual(psbt.validateSignatures(0), true); + psbt.finalizeAllInputs(); // build and broadcast to the RegTest network - await regtestUtils.broadcast(psbt.extractTransaction().toHex()) - }) + await regtestUtils.broadcast(psbt.extractTransaction().toHex()); + }); it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2MS(2 of 4)) (multisig) input', async () => { - const multisig = createPayment('p2sh-p2ms(2 of 4)') - const inputData1 = await getInputData(2e4, multisig.payment, false, 'p2sh') + const multisig = createPayment('p2sh-p2ms(2 of 4)'); + const inputData1 = await getInputData(2e4, multisig.payment, false, 'p2sh'); { const { hash, index, nonWitnessUtxo, redeemScript, // NEW: P2SH needs to give redeemScript when adding an input. - } = inputData1 - assert.deepStrictEqual({ hash, index, nonWitnessUtxo, redeemScript }, inputData1) + } = inputData1; + assert.deepStrictEqual( + { hash, index, nonWitnessUtxo, redeemScript }, + inputData1, + ); } const psbt = new bitcoin.Psbt({ network: regtest }) .addInput(inputData1) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 1e4 + value: 1e4, }) .signInput(0, multisig.keys[0]) - .signInput(0, multisig.keys[2]) + .signInput(0, multisig.keys[2]); - assert.strictEqual(psbt.validateSignatures(0), true) - assert.strictEqual(psbt.validateSignatures(0, multisig.keys[0].publicKey), true) + assert.strictEqual(psbt.validateSignatures(0), true); + assert.strictEqual( + psbt.validateSignatures(0, multisig.keys[0].publicKey), + true, + ); assert.throws(() => { - psbt.validateSignatures(0, multisig.keys[3].publicKey) - }, new RegExp('No signatures for this pubkey')) - psbt.finalizeAllInputs() + psbt.validateSignatures(0, multisig.keys[3].publicKey); + }, new RegExp('No signatures for this pubkey')); + psbt.finalizeAllInputs(); - const tx = psbt.extractTransaction() + const tx = psbt.extractTransaction(); // build and broadcast to the Bitcoin RegTest network - await regtestUtils.broadcast(tx.toHex()) + await regtestUtils.broadcast(tx.toHex()); await regtestUtils.verify({ txId: tx.getId(), address: regtestUtils.RANDOM_ADDRESS, vout: 0, - value: 1e4 - }) - }) + value: 1e4, + }); + }); it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WPKH) input', async () => { - const p2sh = createPayment('p2sh-p2wpkh') - const inputData = await getInputData(5e4, p2sh.payment, true, 'p2sh') + const p2sh = createPayment('p2sh-p2wpkh'); + const inputData = await getInputData(5e4, p2sh.payment, true, 'p2sh'); + const inputData2 = await getInputData(5e4, p2sh.payment, true, 'p2sh'); { const { hash, index, witnessUtxo, // NEW: this is an object of the output being spent { script: Buffer; value: Satoshis; } redeemScript, - } = inputData - assert.deepStrictEqual({ hash, index, witnessUtxo, redeemScript }, inputData) + } = inputData; + assert.deepStrictEqual( + { hash, index, witnessUtxo, redeemScript }, + inputData, + ); } - const keyPair = p2sh.keys[0] + const keyPair = p2sh.keys[0]; const outputData = { script: p2sh.payment.output, // sending to myself for fun - value: 2e4 - } + value: 2e4, + }; + const outputData2 = { + script: p2sh.payment.output, // sending to myself for fun + value: 7e4, + }; const tx = new bitcoin.Psbt() - .addInput(inputData) - .addOutput(outputData) + .addInputs([inputData, inputData2]) + .addOutputs([outputData, outputData2]) .sign(keyPair) .finalizeAllInputs() - .extractTransaction() + .extractTransaction(); // build and broadcast to the Bitcoin RegTest network - await regtestUtils.broadcast(tx.toHex()) + await regtestUtils.broadcast(tx.toHex()); await regtestUtils.verify({ txId: tx.getId(), address: p2sh.payment.address, vout: 0, - value: 2e4 - }) - }) + value: 2e4, + }); + }); it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input', async () => { - // the only thing that changes is you don't give a redeemscript for input data - const p2wpkh = createPayment('p2wpkh') - const inputData = await getInputData(5e4, p2wpkh.payment, true, 'noredeem') + const p2wpkh = createPayment('p2wpkh'); + const inputData = await getInputData(5e4, p2wpkh.payment, true, 'noredeem'); { - const { - hash, - index, - witnessUtxo, - } = inputData - assert.deepStrictEqual({ hash, index, witnessUtxo }, inputData) + const { hash, index, witnessUtxo } = inputData; + assert.deepStrictEqual({ hash, index, witnessUtxo }, inputData); } const psbt = new bitcoin.Psbt({ network: regtest }) .addInput(inputData) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4 + value: 2e4, }) - .signInput(0, p2wpkh.keys[0]) + .signInput(0, p2wpkh.keys[0]); - assert.strictEqual(psbt.validateSignatures(0), true) - psbt.finalizeAllInputs() + assert.strictEqual(psbt.validateSignatures(0), true); + psbt.finalizeAllInputs(); - const tx = psbt.extractTransaction() + const tx = psbt.extractTransaction(); // build and broadcast to the Bitcoin RegTest network - await regtestUtils.broadcast(tx.toHex()) + await regtestUtils.broadcast(tx.toHex()); await regtestUtils.verify({ txId: tx.getId(), address: regtestUtils.RANDOM_ADDRESS, vout: 0, - value: 2e4 - }) - }) + value: 2e4, + }); + }); it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WSH(P2PK) input', async () => { - const p2wsh = createPayment('p2wsh-p2pk') - const inputData = await getInputData(5e4, p2wsh.payment, true, 'p2wsh') + const p2wsh = createPayment('p2wsh-p2pk'); + const inputData = await getInputData(5e4, p2wsh.payment, true, 'p2wsh'); { const { hash, index, witnessUtxo, witnessScript, // NEW: A Buffer of the witnessScript - } = inputData - assert.deepStrictEqual({ hash, index, witnessUtxo, witnessScript }, inputData) + } = inputData; + assert.deepStrictEqual( + { hash, index, witnessUtxo, witnessScript }, + inputData, + ); } const psbt = new bitcoin.Psbt({ network: regtest }) .addInput(inputData) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4 + value: 2e4, }) - .signInput(0, p2wsh.keys[0]) + .signInput(0, p2wsh.keys[0]); - assert.strictEqual(psbt.validateSignatures(0), true) - psbt.finalizeAllInputs() + assert.strictEqual(psbt.validateSignatures(0), true); + psbt.finalizeAllInputs(); - const tx = psbt.extractTransaction() + const tx = psbt.extractTransaction(); // build and broadcast to the Bitcoin RegTest network - await regtestUtils.broadcast(tx.toHex()) + await regtestUtils.broadcast(tx.toHex()); await regtestUtils.verify({ txId: tx.getId(), address: regtestUtils.RANDOM_ADDRESS, vout: 0, - value: 2e4 - }) - }) + value: 2e4, + }); + }); it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WSH(P2MS(3 of 4))) (SegWit multisig) input', async () => { - const p2sh = createPayment('p2sh-p2wsh-p2ms(3 of 4)') - const inputData = await getInputData(5e4, p2sh.payment, true, 'p2sh-p2wsh') + const p2sh = createPayment('p2sh-p2wsh-p2ms(3 of 4)'); + const inputData = await getInputData(5e4, p2sh.payment, true, 'p2sh-p2wsh'); { const { hash, @@ -335,54 +364,60 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { witnessUtxo, redeemScript, witnessScript, - } = inputData - assert.deepStrictEqual({ hash, index, witnessUtxo, redeemScript, witnessScript }, inputData) + } = inputData; + assert.deepStrictEqual( + { hash, index, witnessUtxo, redeemScript, witnessScript }, + inputData, + ); } const psbt = new bitcoin.Psbt({ network: regtest }) .addInput(inputData) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4 + value: 2e4, }) .signInput(0, p2sh.keys[0]) .signInput(0, p2sh.keys[2]) - .signInput(0, p2sh.keys[3]) + .signInput(0, p2sh.keys[3]); - assert.strictEqual(psbt.validateSignatures(0), true) - assert.strictEqual(psbt.validateSignatures(0, p2sh.keys[3].publicKey), true) + assert.strictEqual(psbt.validateSignatures(0), true); + assert.strictEqual( + psbt.validateSignatures(0, p2sh.keys[3].publicKey), + true, + ); assert.throws(() => { - psbt.validateSignatures(0, p2sh.keys[1].publicKey) - }, new RegExp('No signatures for this pubkey')) - psbt.finalizeAllInputs() + psbt.validateSignatures(0, p2sh.keys[1].publicKey); + }, new RegExp('No signatures for this pubkey')); + psbt.finalizeAllInputs(); - const tx = psbt.extractTransaction() + const tx = psbt.extractTransaction(); // build and broadcast to the Bitcoin RegTest network - await regtestUtils.broadcast(tx.toHex()) + await regtestUtils.broadcast(tx.toHex()); await regtestUtils.verify({ txId: tx.getId(), address: regtestUtils.RANDOM_ADDRESS, vout: 0, - value: 2e4 - }) - }) -}) + value: 2e4, + }); + }); +}); function createPayment(_type, network) { - network = network || regtest + network = network || regtest; const splitType = _type.split('-').reverse(); const isMultisig = splitType[0].slice(0, 4) === 'p2ms'; const keys = []; let m; if (isMultisig) { - const match = splitType[0].match(/^p2ms\((\d+) of (\d+)\)$/) - m = parseInt(match[1]) - let n = parseInt(match[2]) + const match = splitType[0].match(/^p2ms\((\d+) of (\d+)\)$/); + m = parseInt(match[1]); + let n = parseInt(match[2]); while (n > 1) { keys.push(bitcoin.ECPair.makeRandom({ network })); - n-- + n--; } } keys.push(bitcoin.ECPair.makeRandom({ network })); diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index 61ed15e..bfe340c 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -130,6 +130,13 @@ export class Psbt extends PsbtBase { return this.inputs.length; } + clone(): Psbt { + // TODO: more efficient cloning + const res = Psbt.fromBuffer(this.toBuffer()); + res.opts = JSON.parse(JSON.stringify(this.opts)); + return res; + } + setMaximumFeeRate(satoshiPerByte: number): void { check32Bit(satoshiPerByte); // 42.9 BTC per byte IS excessive... so throw this.opts.maximumFeeRate = satoshiPerByte; @@ -168,6 +175,11 @@ export class Psbt extends PsbtBase { return this; } + addInputs(inputDatas: TransactionInput[]): this { + inputDatas.forEach(inputData => this.addInput(inputData)); + return this; + } + addInput(inputData: TransactionInput): this { checkInputsForPartialSig(this.inputs, 'addInput'); const c = this.__CACHE; @@ -178,6 +190,11 @@ export class Psbt extends PsbtBase { return this; } + addOutputs(outputDatas: TransactionOutput[]): this { + outputDatas.forEach(outputData => this.addOutput(outputData)); + return this; + } + addOutput(outputData: TransactionOutput): this { checkInputsForPartialSig(this.inputs, 'addOutput'); const { address } = outputData as any; diff --git a/types/psbt.d.ts b/types/psbt.d.ts index 40571fa..10617c2 100644 --- a/types/psbt.d.ts +++ b/types/psbt.d.ts @@ -11,11 +11,14 @@ export declare class Psbt extends PsbtBase { private opts; constructor(opts?: PsbtOptsOptional); readonly inputCount: number; + clone(): Psbt; setMaximumFeeRate(satoshiPerByte: number): void; setVersion(version: number): this; setLocktime(locktime: number): this; setSequence(inputIndex: number, sequence: number): this; + addInputs(inputDatas: TransactionInput[]): this; addInput(inputData: TransactionInput): this; + addOutputs(outputDatas: TransactionOutput[]): this; addOutput(outputData: TransactionOutput): this; addNonWitnessUtxoToInput(inputIndex: number, nonWitnessUtxo: NonWitnessUtxo): this; extractTransaction(disableFeeCheck?: boolean): Transaction;