diff --git a/src/psbt.js b/src/psbt.js index 57a159c..3326995 100644 --- a/src/psbt.js +++ b/src/psbt.js @@ -204,7 +204,18 @@ class Psbt { range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx)); return this; } - finalizeInput(inputIndex) { + finalizeInput( + inputIndex, + { + classifyScript: classifyScriptF, + canFinalize: canFinalizeF, + getFinalScripts: getFinalScriptsF, + } = { + classifyScript, + canFinalize, + getFinalScripts, + }, + ) { const input = utils_1.checkForInput(this.data.inputs, inputIndex); const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput( inputIndex, @@ -212,11 +223,11 @@ class Psbt { this.__CACHE, ); if (!script) throw new Error(`No script found for input #${inputIndex}`); - const scriptType = classifyScript(script); - if (!canFinalize(input, script, scriptType)) + const scriptType = classifyScriptF(script); + if (!canFinalizeF(input, script, scriptType)) throw new Error(`Can not finalize input #${inputIndex}`); checkPartialSigSighashes(input); - const { finalScriptSig, finalScriptWitness } = getFinalScripts( + const { finalScriptSig, finalScriptWitness } = getFinalScriptsF( script, scriptType, input.partialSig, diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index d35fd4c..6fa6f43 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -251,7 +251,18 @@ export class Psbt { return this; } - finalizeInput(inputIndex: number): this { + finalizeInput( + inputIndex: number, + { + classifyScript: classifyScriptF, + canFinalize: canFinalizeF, + getFinalScripts: getFinalScriptsF, + }: IFinalizeFuncs = { + classifyScript, + canFinalize, + getFinalScripts, + }, + ): this { const input = checkForInput(this.data.inputs, inputIndex); const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput( inputIndex, @@ -260,13 +271,13 @@ export class Psbt { ); if (!script) throw new Error(`No script found for input #${inputIndex}`); - const scriptType = classifyScript(script); - if (!canFinalize(input, script, scriptType)) + const scriptType = classifyScriptF(script); + if (!canFinalizeF(input, script, scriptType)) throw new Error(`Can not finalize input #${inputIndex}`); checkPartialSigSighashes(input); - const { finalScriptSig, finalScriptWitness } = getFinalScripts( + const { finalScriptSig, finalScriptWitness } = getFinalScriptsF( script, scriptType, input.partialSig!, @@ -735,6 +746,39 @@ class PsbtTransaction implements ITransaction { } } +// This interface is added to allow for custom scripts to be finalized with PSBT. +interface IFinalizeFuncs { + classifyScript: FinalizeFuncClassifyScript; + canFinalize: FinalizeFuncCanFinalize; + getFinalScripts: FinalizeFuncGetFinalScripts; +} + +// Takes the meaningful script (redeemScript for P2SH and witnessScript for P2WSH) +// and returns a string to classify the script. +type FinalizeFuncClassifyScript = (script: Buffer) => string; +// Takes the Psbt data for the input and the meaningful script and its type name. +// returns true if we can finalize the input +type FinalizeFuncCanFinalize = ( + input: PsbtInput, + script: Buffer, + scriptType: string, +) => boolean; +// Takes the meaningful script, its type name, all the signatures from this input, +// and 3 booleans to tell you if it is segwit, P2SH, and P2WSH. +// it returns finalScriptSig and finalScriptWitness to be placed in the Psbt. +// if one is not needed, it should be undefined. (In TypeScript, it must be declared but undefined.) +type FinalizeFuncGetFinalScripts = ( + script: Buffer, + scriptType: string, + partialSig: PartialSig[], + isSegwit: boolean, + isP2SH: boolean, + isP2WSH: boolean, +) => { + finalScriptSig: Buffer | undefined; + finalScriptWitness: Buffer | undefined; +}; + function canFinalize( input: PsbtInput, script: Buffer, diff --git a/types/psbt.d.ts b/types/psbt.d.ts index b1bacea..516d72f 100644 --- a/types/psbt.d.ts +++ b/types/psbt.d.ts @@ -1,5 +1,5 @@ import { Psbt as PsbtBase } from 'bip174'; -import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate, TransactionInput } from 'bip174/src/lib/interfaces'; +import { KeyValue, PartialSig, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate, TransactionInput } from 'bip174/src/lib/interfaces'; import { Signer, SignerAsync } from './ecpair'; import { Network } from './networks'; import { Transaction } from './transaction'; @@ -58,7 +58,7 @@ export declare class Psbt { getFeeRate(): number; getFee(): number; finalizeAllInputs(): this; - finalizeInput(inputIndex: number): this; + finalizeInput(inputIndex: number, { classifyScript: classifyScriptF, canFinalize: canFinalizeF, getFinalScripts: getFinalScriptsF, }?: IFinalizeFuncs): this; validateSignaturesOfAllInputs(): boolean; validateSignaturesOfInput(inputIndex: number, pubkey?: Buffer): boolean; signAllInputsHD(hdKeyPair: HDSigner, sighashTypes?: number[]): this; @@ -124,4 +124,15 @@ interface HDSignerAsync extends HDSignerBase { derivePath(path: string): HDSignerAsync; sign(hash: Buffer): Promise; } +interface IFinalizeFuncs { + classifyScript: FinalizeFuncClassifyScript; + canFinalize: FinalizeFuncCanFinalize; + getFinalScripts: FinalizeFuncGetFinalScripts; +} +declare type FinalizeFuncClassifyScript = (script: Buffer) => string; +declare type FinalizeFuncCanFinalize = (input: PsbtInput, script: Buffer, scriptType: string) => boolean; +declare type FinalizeFuncGetFinalScripts = (script: Buffer, scriptType: string, partialSig: PartialSig[], isSegwit: boolean, isP2SH: boolean, isP2WSH: boolean) => { + finalScriptSig: Buffer | undefined; + finalScriptWitness: Buffer | undefined; +}; export {};