diff --git a/src/psbt.js b/src/psbt.js index 59d898c..ae60861 100644 --- a/src/psbt.js +++ b/src/psbt.js @@ -56,24 +56,14 @@ class Psbt extends bip174_1.Psbt { if (!script) return false; const scriptType = classifyScript(script); if (!canFinalize(input, script, scriptType)) return false; - let finalScriptSig; - let finalScriptWitness; - // Wow, the payments API is very handy - const payment = getPayment(script, scriptType, input.partialSig); - const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment }); - const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment }); - if (isSegwit) { - if (p2wsh) { - finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness); - } else { - finalScriptWitness = witnessStackToScriptWitness(payment.witness); - } - if (p2sh) { - finalScriptSig = bscript.compile([p2sh.redeem.output]); - } - } else { - finalScriptSig = payment.input; - } + const { finalScriptSig, finalScriptWitness } = getFinalScripts( + script, + scriptType, + input.partialSig, + isSegwit, + isP2SH, + isP2WSH, + ); if (finalScriptSig) this.addFinalScriptSigToInput(inputIndex, finalScriptSig); if (finalScriptWitness) @@ -83,22 +73,38 @@ class Psbt extends bip174_1.Psbt { return true; } signInput(inputIndex, keyPair) { - const input = utils_1.checkForInput(this.inputs, inputIndex); if (!keyPair || !keyPair.publicKey) throw new Error('Need Signer to sign input'); - const { hash, sighashType, script } = getHashForSig( + const { hash, sighashType } = getHashAndSighashType( + this.inputs, inputIndex, - input, + keyPair.publicKey, this.globalMap.unsignedTx, ); - const pubkey = keyPair.publicKey; - checkScriptForPubkey(pubkey, script); const partialSig = { - pubkey, + pubkey: keyPair.publicKey, signature: bscript.signature.encode(keyPair.sign(hash), sighashType), }; return this.addPartialSigToInput(inputIndex, partialSig); } + async signInputAsync(inputIndex, keyPair) { + if (!keyPair || !keyPair.publicKey) + throw new Error('Need Signer to sign input'); + const { hash, sighashType } = getHashAndSighashType( + this.inputs, + inputIndex, + keyPair.publicKey, + this.globalMap.unsignedTx, + ); + const partialSig = { + pubkey: keyPair.publicKey, + signature: bscript.signature.encode( + await keyPair.sign(hash), + sighashType, + ), + }; + this.addPartialSigToInput(inputIndex, partialSig); + } } exports.Psbt = Psbt; // @@ -113,6 +119,46 @@ exports.Psbt = Psbt; function isFinalized(input) { return !!input.finalScriptSig || !!input.finalScriptWitness; } +function getHashAndSighashType(inputs, inputIndex, pubkey, txBuf) { + const input = utils_1.checkForInput(inputs, inputIndex); + const { hash, sighashType, script } = getHashForSig(inputIndex, input, txBuf); + checkScriptForPubkey(pubkey, script); + return { + hash, + sighashType, + }; +} +function getFinalScripts( + script, + scriptType, + partialSig, + isSegwit, + isP2SH, + isP2WSH, +) { + let finalScriptSig; + let finalScriptWitness; + // Wow, the payments API is very handy + const payment = getPayment(script, scriptType, partialSig); + const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment }); + const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment }); + if (isSegwit) { + if (p2wsh) { + finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness); + } else { + finalScriptWitness = witnessStackToScriptWitness(payment.witness); + } + if (p2sh) { + finalScriptSig = bscript.compile([p2sh.redeem.output]); + } + } else { + finalScriptSig = payment.input; + } + return { + finalScriptSig, + finalScriptWitness, + }; +} function getPayment(script, scriptType, partialSig) { let payment; switch (scriptType) { diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index 273a1c3..d9a059c 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -2,7 +2,7 @@ import { Psbt as PsbtBase } from 'bip174'; import { PartialSig, PsbtInput } from 'bip174/src/lib/interfaces'; import { checkForInput } from 'bip174/src/lib/utils'; import { hash160 } from './crypto'; -import { Signer } from './ecpair'; +import { Signer, SignerAsync } from './ecpair'; import { Network } from './networks'; import * as payments from './payments'; import * as bscript from './script'; @@ -65,30 +65,14 @@ export class Psbt extends PsbtBase { const scriptType = classifyScript(script); if (!canFinalize(input, script, scriptType)) return false; - let finalScriptSig: Buffer | undefined; - let finalScriptWitness: Buffer | undefined; - - // Wow, the payments API is very handy - const payment: payments.Payment = getPayment( + const { finalScriptSig, finalScriptWitness } = getFinalScripts( script, scriptType, input.partialSig!, + isSegwit, + isP2SH, + isP2WSH, ); - const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment }); - const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment }); - - if (isSegwit) { - if (p2wsh) { - finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness!); - } else { - finalScriptWitness = witnessStackToScriptWitness(payment.witness!); - } - if (p2sh) { - finalScriptSig = bscript.compile([p2sh.redeem!.output!]); - } - } else { - finalScriptSig = payment.input; - } if (finalScriptSig) this.addFinalScriptSigToInput(inputIndex, finalScriptSig); @@ -101,26 +85,46 @@ export class Psbt extends PsbtBase { } signInput(inputIndex: number, keyPair: Signer): Psbt { - const input = checkForInput(this.inputs, inputIndex); if (!keyPair || !keyPair.publicKey) throw new Error('Need Signer to sign input'); - const { hash, sighashType, script } = getHashForSig( + const { hash, sighashType } = getHashAndSighashType( + this.inputs, inputIndex, - input, + keyPair.publicKey, this.globalMap.unsignedTx!, ); - const pubkey = keyPair.publicKey; - - checkScriptForPubkey(pubkey, script); - const partialSig = { - pubkey, + pubkey: keyPair.publicKey, signature: bscript.signature.encode(keyPair.sign(hash), sighashType), }; return this.addPartialSigToInput(inputIndex, partialSig); } + + async signInputAsync( + inputIndex: number, + keyPair: SignerAsync, + ): Promise { + if (!keyPair || !keyPair.publicKey) + throw new Error('Need Signer to sign input'); + const { hash, sighashType } = getHashAndSighashType( + this.inputs, + inputIndex, + keyPair.publicKey, + this.globalMap.unsignedTx!, + ); + + const partialSig = { + pubkey: keyPair.publicKey, + signature: bscript.signature.encode( + await keyPair.sign(hash), + sighashType, + ), + }; + + this.addPartialSigToInput(inputIndex, partialSig); + } } // @@ -137,6 +141,61 @@ function isFinalized(input: PsbtInput): boolean { return !!input.finalScriptSig || !!input.finalScriptWitness; } +function getHashAndSighashType( + inputs: PsbtInput[], + inputIndex: number, + pubkey: Buffer, + txBuf: Buffer, +): { + hash: Buffer; + sighashType: number; +} { + const input = checkForInput(inputs, inputIndex); + const { hash, sighashType, script } = getHashForSig(inputIndex, input, txBuf); + checkScriptForPubkey(pubkey, script); + return { + hash, + sighashType, + }; +} + +function getFinalScripts( + script: Buffer, + scriptType: string, + partialSig: PartialSig[], + isSegwit: boolean, + isP2SH: boolean, + isP2WSH: boolean, +): { + finalScriptSig: Buffer | undefined; + finalScriptWitness: Buffer | undefined; +} { + let finalScriptSig: Buffer | undefined; + let finalScriptWitness: Buffer | undefined; + + // Wow, the payments API is very handy + const payment: payments.Payment = getPayment(script, scriptType, partialSig); + const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment }); + const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment }); + + if (isSegwit) { + if (p2wsh) { + finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness!); + } else { + finalScriptWitness = witnessStackToScriptWitness(payment.witness!); + } + if (p2sh) { + finalScriptSig = bscript.compile([p2sh.redeem!.output!]); + } + } else { + finalScriptSig = payment.input; + } + return { + finalScriptSig, + finalScriptWitness, + }; +} + function getPayment( script: Buffer, scriptType: string, diff --git a/tsconfig.json b/tsconfig.json index f770a45..1de632d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES2015", + "target": "ES2017", "module": "commonjs", "outDir": "./src", "declaration": true, diff --git a/types/psbt.d.ts b/types/psbt.d.ts index f5b6430..26ae0a7 100644 --- a/types/psbt.d.ts +++ b/types/psbt.d.ts @@ -1,5 +1,5 @@ import { Psbt as PsbtBase } from 'bip174'; -import { Signer } from './ecpair'; +import { Signer, SignerAsync } from './ecpair'; import { Network } from './networks'; import { Transaction } from './transaction'; export declare class Psbt extends PsbtBase { @@ -12,4 +12,5 @@ export declare class Psbt extends PsbtBase { }; finalizeInput(inputIndex: number): boolean; signInput(inputIndex: number, keyPair: Signer): Psbt; + signInputAsync(inputIndex: number, keyPair: SignerAsync): Promise; }