Add async signing method
This commit is contained in:
parent
813b84f91f
commit
77dde89acc
4 changed files with 161 additions and 55 deletions
94
src/psbt.js
94
src/psbt.js
|
@ -56,24 +56,14 @@ class Psbt extends bip174_1.Psbt {
|
||||||
if (!script) return false;
|
if (!script) return false;
|
||||||
const scriptType = classifyScript(script);
|
const scriptType = classifyScript(script);
|
||||||
if (!canFinalize(input, script, scriptType)) return false;
|
if (!canFinalize(input, script, scriptType)) return false;
|
||||||
let finalScriptSig;
|
const { finalScriptSig, finalScriptWitness } = getFinalScripts(
|
||||||
let finalScriptWitness;
|
script,
|
||||||
// Wow, the payments API is very handy
|
scriptType,
|
||||||
const payment = getPayment(script, scriptType, input.partialSig);
|
input.partialSig,
|
||||||
const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment });
|
isSegwit,
|
||||||
const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
|
isP2SH,
|
||||||
if (isSegwit) {
|
isP2WSH,
|
||||||
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)
|
if (finalScriptSig)
|
||||||
this.addFinalScriptSigToInput(inputIndex, finalScriptSig);
|
this.addFinalScriptSigToInput(inputIndex, finalScriptSig);
|
||||||
if (finalScriptWitness)
|
if (finalScriptWitness)
|
||||||
|
@ -83,22 +73,38 @@ class Psbt extends bip174_1.Psbt {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
signInput(inputIndex, keyPair) {
|
signInput(inputIndex, keyPair) {
|
||||||
const input = utils_1.checkForInput(this.inputs, inputIndex);
|
|
||||||
if (!keyPair || !keyPair.publicKey)
|
if (!keyPair || !keyPair.publicKey)
|
||||||
throw new Error('Need Signer to sign input');
|
throw new Error('Need Signer to sign input');
|
||||||
const { hash, sighashType, script } = getHashForSig(
|
const { hash, sighashType } = getHashAndSighashType(
|
||||||
|
this.inputs,
|
||||||
inputIndex,
|
inputIndex,
|
||||||
input,
|
keyPair.publicKey,
|
||||||
this.globalMap.unsignedTx,
|
this.globalMap.unsignedTx,
|
||||||
);
|
);
|
||||||
const pubkey = keyPair.publicKey;
|
|
||||||
checkScriptForPubkey(pubkey, script);
|
|
||||||
const partialSig = {
|
const partialSig = {
|
||||||
pubkey,
|
pubkey: keyPair.publicKey,
|
||||||
signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
|
signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
|
||||||
};
|
};
|
||||||
return this.addPartialSigToInput(inputIndex, partialSig);
|
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;
|
exports.Psbt = Psbt;
|
||||||
//
|
//
|
||||||
|
@ -113,6 +119,46 @@ exports.Psbt = Psbt;
|
||||||
function isFinalized(input) {
|
function isFinalized(input) {
|
||||||
return !!input.finalScriptSig || !!input.finalScriptWitness;
|
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) {
|
function getPayment(script, scriptType, partialSig) {
|
||||||
let payment;
|
let payment;
|
||||||
switch (scriptType) {
|
switch (scriptType) {
|
||||||
|
|
117
ts_src/psbt.ts
117
ts_src/psbt.ts
|
@ -2,7 +2,7 @@ import { Psbt as PsbtBase } from 'bip174';
|
||||||
import { PartialSig, PsbtInput } from 'bip174/src/lib/interfaces';
|
import { PartialSig, PsbtInput } from 'bip174/src/lib/interfaces';
|
||||||
import { checkForInput } from 'bip174/src/lib/utils';
|
import { checkForInput } from 'bip174/src/lib/utils';
|
||||||
import { hash160 } from './crypto';
|
import { hash160 } from './crypto';
|
||||||
import { Signer } from './ecpair';
|
import { Signer, SignerAsync } from './ecpair';
|
||||||
import { Network } from './networks';
|
import { Network } from './networks';
|
||||||
import * as payments from './payments';
|
import * as payments from './payments';
|
||||||
import * as bscript from './script';
|
import * as bscript from './script';
|
||||||
|
@ -65,30 +65,14 @@ export class Psbt extends PsbtBase {
|
||||||
const scriptType = classifyScript(script);
|
const scriptType = classifyScript(script);
|
||||||
if (!canFinalize(input, script, scriptType)) return false;
|
if (!canFinalize(input, script, scriptType)) return false;
|
||||||
|
|
||||||
let finalScriptSig: Buffer | undefined;
|
const { finalScriptSig, finalScriptWitness } = getFinalScripts(
|
||||||
let finalScriptWitness: Buffer | undefined;
|
|
||||||
|
|
||||||
// Wow, the payments API is very handy
|
|
||||||
const payment: payments.Payment = getPayment(
|
|
||||||
script,
|
script,
|
||||||
scriptType,
|
scriptType,
|
||||||
input.partialSig!,
|
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)
|
if (finalScriptSig)
|
||||||
this.addFinalScriptSigToInput(inputIndex, finalScriptSig);
|
this.addFinalScriptSigToInput(inputIndex, finalScriptSig);
|
||||||
|
@ -101,26 +85,46 @@ export class Psbt extends PsbtBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
signInput(inputIndex: number, keyPair: Signer): Psbt {
|
signInput(inputIndex: number, keyPair: Signer): Psbt {
|
||||||
const input = checkForInput(this.inputs, inputIndex);
|
|
||||||
if (!keyPair || !keyPair.publicKey)
|
if (!keyPair || !keyPair.publicKey)
|
||||||
throw new Error('Need Signer to sign input');
|
throw new Error('Need Signer to sign input');
|
||||||
const { hash, sighashType, script } = getHashForSig(
|
const { hash, sighashType } = getHashAndSighashType(
|
||||||
|
this.inputs,
|
||||||
inputIndex,
|
inputIndex,
|
||||||
input,
|
keyPair.publicKey,
|
||||||
this.globalMap.unsignedTx!,
|
this.globalMap.unsignedTx!,
|
||||||
);
|
);
|
||||||
|
|
||||||
const pubkey = keyPair.publicKey;
|
|
||||||
|
|
||||||
checkScriptForPubkey(pubkey, script);
|
|
||||||
|
|
||||||
const partialSig = {
|
const partialSig = {
|
||||||
pubkey,
|
pubkey: keyPair.publicKey,
|
||||||
signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
|
signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.addPartialSigToInput(inputIndex, partialSig);
|
return this.addPartialSigToInput(inputIndex, partialSig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async signInputAsync(
|
||||||
|
inputIndex: number,
|
||||||
|
keyPair: SignerAsync,
|
||||||
|
): Promise<void> {
|
||||||
|
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;
|
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(
|
function getPayment(
|
||||||
script: Buffer,
|
script: Buffer,
|
||||||
scriptType: string,
|
scriptType: string,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2015",
|
"target": "ES2017",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"outDir": "./src",
|
"outDir": "./src",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
|
|
3
types/psbt.d.ts
vendored
3
types/psbt.d.ts
vendored
|
@ -1,5 +1,5 @@
|
||||||
import { Psbt as PsbtBase } from 'bip174';
|
import { Psbt as PsbtBase } from 'bip174';
|
||||||
import { Signer } from './ecpair';
|
import { Signer, SignerAsync } from './ecpair';
|
||||||
import { Network } from './networks';
|
import { Network } from './networks';
|
||||||
import { Transaction } from './transaction';
|
import { Transaction } from './transaction';
|
||||||
export declare class Psbt extends PsbtBase {
|
export declare class Psbt extends PsbtBase {
|
||||||
|
@ -12,4 +12,5 @@ export declare class Psbt extends PsbtBase {
|
||||||
};
|
};
|
||||||
finalizeInput(inputIndex: number): boolean;
|
finalizeInput(inputIndex: number): boolean;
|
||||||
signInput(inputIndex: number, keyPair: Signer): Psbt;
|
signInput(inputIndex: number, keyPair: Signer): Psbt;
|
||||||
|
signInputAsync(inputIndex: number, keyPair: SignerAsync): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue