From 2b8e8001bc6d8ebbafa83067119e4b229f5d8ef9 Mon Sep 17 00:00:00 2001 From: junderw Date: Thu, 4 Jul 2019 11:26:23 +0900 Subject: [PATCH] Support Addresses for outputs --- src/psbt.js | 28 ++++++++++++++++------------ ts_src/psbt.ts | 48 +++++++++++++++++++++++++++++++++++++++++++++--- types/psbt.d.ts | 12 ++++++++++-- 3 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/psbt.js b/src/psbt.js index 3cbd899..d47bdb2 100644 --- a/src/psbt.js +++ b/src/psbt.js @@ -2,16 +2,17 @@ Object.defineProperty(exports, '__esModule', { value: true }); const bip174_1 = require('bip174'); const utils_1 = require('bip174/src/lib/utils'); +const address_1 = require('./address'); const crypto_1 = require('./crypto'); +const networks_1 = require('./networks'); const payments = require('./payments'); const bscript = require('./script'); const transaction_1 = require('./transaction'); const varuint = require('varuint-bitcoin'); class Psbt extends bip174_1.Psbt { - // protected __TX: Transaction; - constructor(network) { + constructor(opts = {}) { super(); - this.network = network; + this.opts = Object.assign({}, DEFAULT_OPTS, opts); // // TODO: figure out a way to use a Transaction Object instead of a Buffer // // TODO: Caching, since .toBuffer() calls every time we get is lame. // this.__TX = Transaction.fromBuffer(this.globalMap.unsignedTx!); @@ -24,6 +25,15 @@ class Psbt extends bip174_1.Psbt { // } // }); } + addOutput(outputData, allowNoInput = false, transactionOutputAdder) { + const { address } = outputData; + if (typeof address === 'string') { + const { network } = this.opts; + const script = address_1.toOutputScript(address, network); + outputData = Object.assign(outputData, { script }); + } + return super.addOutput(outputData, allowNoInput, transactionOutputAdder); + } extractTransaction() { if (!this.inputs.every(isFinalized)) throw new Error('Not finalized'); const tx = transaction_1.Transaction.fromBuffer(this.globalMap.unsignedTx); @@ -107,15 +117,9 @@ class Psbt extends bip174_1.Psbt { } } exports.Psbt = Psbt; -// -// -// -// -// Helper functions -// -// -// -// +const DEFAULT_OPTS = { + network: networks_1.bitcoin, +}; function isFinalized(input) { return !!input.finalScriptSig || !!input.finalScriptWitness; } diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index 7c60a1d..eff576b 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -1,9 +1,14 @@ import { Psbt as PsbtBase } from 'bip174'; -import { PartialSig, PsbtInput } from 'bip174/src/lib/interfaces'; +import { + PartialSig, + PsbtInput, + TransactionOutput, +} from 'bip174/src/lib/interfaces'; import { checkForInput } from 'bip174/src/lib/utils'; +import { toOutputScript } from './address'; import { hash160 } from './crypto'; import { Signer, SignerAsync } from './ecpair'; -import { Network } from './networks'; +import { bitcoin as btcNetwork, Network } from './networks'; import * as payments from './payments'; import * as bscript from './script'; import { Transaction } from './transaction'; @@ -11,8 +16,10 @@ const varuint = require('varuint-bitcoin'); export class Psbt extends PsbtBase { // protected __TX: Transaction; - constructor(public network?: Network) { + private opts: PsbtOpts; + constructor(opts: PsbtOptsOptional = {}) { super(); + this.opts = Object.assign({}, DEFAULT_OPTS, opts); // // TODO: figure out a way to use a Transaction Object instead of a Buffer // // TODO: Caching, since .toBuffer() calls every time we get is lame. // this.__TX = Transaction.fromBuffer(this.globalMap.unsignedTx!); @@ -26,6 +33,29 @@ export class Psbt extends PsbtBase { // }); } + addOutput(outputData: TransactionOutput, allowNoInput?: boolean): this; + addOutput( + outputData: T, + allowNoInput?: boolean, + transactionOutputAdder?: (output: T, txBuffer: Buffer) => Buffer, + ): this; + addOutput( + outputData: T | TransactionOutput, + allowNoInput: boolean = false, + transactionOutputAdder?: ( + output: T | TransactionOutput, + txBuffer: Buffer, + ) => Buffer, + ): this { + const { address } = outputData as any; + if (typeof address === 'string') { + const { network } = this.opts; + const script = toOutputScript(address, network); + outputData = Object.assign(outputData, { script }); + } + return super.addOutput(outputData, allowNoInput, transactionOutputAdder); + } + extractTransaction(): Transaction { if (!this.inputs.every(isFinalized)) throw new Error('Not finalized'); const tx = Transaction.fromBuffer(this.globalMap.unsignedTx!); @@ -134,6 +164,18 @@ export class Psbt extends PsbtBase { // // +interface PsbtOptsOptional { + network?: Network; +} + +interface PsbtOpts { + network: Network; +} + +const DEFAULT_OPTS = { + network: btcNetwork, +}; + function isFinalized(input: PsbtInput): boolean { return !!input.finalScriptSig || !!input.finalScriptWitness; } diff --git a/types/psbt.d.ts b/types/psbt.d.ts index 26ae0a7..6275ee3 100644 --- a/types/psbt.d.ts +++ b/types/psbt.d.ts @@ -1,10 +1,14 @@ +/// import { Psbt as PsbtBase } from 'bip174'; +import { TransactionOutput } from 'bip174/src/lib/interfaces'; import { Signer, SignerAsync } from './ecpair'; import { Network } from './networks'; import { Transaction } from './transaction'; export declare class Psbt extends PsbtBase { - network?: Network | undefined; - constructor(network?: Network | undefined); + private opts; + constructor(opts?: PsbtOptsOptional); + addOutput(outputData: TransactionOutput, allowNoInput?: boolean): this; + addOutput(outputData: T, allowNoInput?: boolean, transactionOutputAdder?: (output: T, txBuffer: Buffer) => Buffer): this; extractTransaction(): Transaction; finalizeAllInputs(): { result: boolean; @@ -14,3 +18,7 @@ export declare class Psbt extends PsbtBase { signInput(inputIndex: number, keyPair: Signer): Psbt; signInputAsync(inputIndex: number, keyPair: SignerAsync): Promise; } +interface PsbtOptsOptional { + network?: Network; +} +export {};