Start towards finalizing inputs
This commit is contained in:
parent
f87b66eb24
commit
f72c915ff1
5 changed files with 125 additions and 13 deletions
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -200,9 +200,9 @@
|
|||
}
|
||||
},
|
||||
"bip174": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/bip174/-/bip174-0.0.8.tgz",
|
||||
"integrity": "sha512-xWPzmlCvLoOWTlXk1wG7+TyOfaN8xX07IieuG4ug5su3igC9s4Lsdq+IEEMo+YHDQ4hPPAX9LYio6aEIAA+Zrg=="
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/bip174/-/bip174-0.0.10.tgz",
|
||||
"integrity": "sha512-gFtSEMayg7HPKGnIQcEx5CqD/qHWuMlxLJ/+VV4k4Q2mcA0rY040JbNpFuCGVI6rJYv211f0NA7nkU4xkPX4nQ=="
|
||||
},
|
||||
"bip32": {
|
||||
"version": "2.0.3",
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
"dependencies": {
|
||||
"@types/node": "10.12.18",
|
||||
"bech32": "^1.1.2",
|
||||
"bip174": "0.0.8",
|
||||
"bip174": "0.0.10",
|
||||
"bip32": "^2.0.3",
|
||||
"bip66": "^1.1.0",
|
||||
"bitcoin-ops": "^1.4.0",
|
||||
|
|
60
src/psbt.js
60
src/psbt.js
|
@ -1,6 +1,8 @@
|
|||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
const bip174_1 = require('bip174');
|
||||
const utils_1 = require('bip174/src/lib/utils');
|
||||
const classify = require('./classify');
|
||||
const payments = require('./payments');
|
||||
const bscript = require('./script');
|
||||
const transaction_1 = require('./transaction');
|
||||
|
@ -23,17 +25,67 @@ const checkWitnessScript = scriptCheckerFactory(
|
|||
payments.p2wsh,
|
||||
'Witness script',
|
||||
);
|
||||
const isP2WPKH = script => {
|
||||
const isPayment = (script, payment) => {
|
||||
try {
|
||||
payments.p2wpkh({ output: script });
|
||||
payment({ output: script });
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
function getScriptFromInput(inputIndex, input, _unsignedTx) {
|
||||
let script;
|
||||
if (input.nonWitnessUtxo) {
|
||||
if (input.redeemScript) {
|
||||
script = input.redeemScript;
|
||||
} else {
|
||||
const unsignedTx = transaction_1.Transaction.fromBuffer(_unsignedTx);
|
||||
const nonWitnessUtxoTx = transaction_1.Transaction.fromBuffer(
|
||||
input.nonWitnessUtxo,
|
||||
);
|
||||
const prevoutIndex = unsignedTx.ins[inputIndex].index;
|
||||
script = nonWitnessUtxoTx.outs[prevoutIndex].script;
|
||||
}
|
||||
} else if (input.witnessUtxo) {
|
||||
if (input.witnessScript) {
|
||||
script = input.witnessScript;
|
||||
} else if (input.redeemScript) {
|
||||
script = payments.p2pkh({ hash: input.redeemScript.slice(2) }).output;
|
||||
} else {
|
||||
script = payments.p2pkh({ hash: input.witnessUtxo.script.slice(2) })
|
||||
.output;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
return script;
|
||||
}
|
||||
class Psbt extends bip174_1.Psbt {
|
||||
constructor() {
|
||||
constructor(network) {
|
||||
super();
|
||||
this.network = network;
|
||||
}
|
||||
canFinalize(inputIndex) {
|
||||
const input = utils_1.checkForInput(this.inputs, inputIndex);
|
||||
const script = getScriptFromInput(
|
||||
inputIndex,
|
||||
input,
|
||||
this.globalMap.unsignedTx,
|
||||
);
|
||||
if (!script) return false;
|
||||
const scriptType = classify.output(script);
|
||||
switch (scriptType) {
|
||||
case 'pubkey':
|
||||
return false;
|
||||
case 'pubkeyhash':
|
||||
return false;
|
||||
case 'multisig':
|
||||
return false;
|
||||
case 'witnesspubkeyhash':
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
signInput(inputIndex, keyPair) {
|
||||
// TODO: Implement BIP174 pre-sign checks:
|
||||
|
@ -108,7 +160,7 @@ class Psbt extends bip174_1.Psbt {
|
|||
} else {
|
||||
script = input.witnessUtxo.script;
|
||||
}
|
||||
if (isP2WPKH(script)) {
|
||||
if (isPayment(script, payments.p2wpkh)) {
|
||||
// P2WPKH uses the P2PKH template for prevoutScript when signing
|
||||
const signingScript = payments.p2pkh({ hash: script.slice(2) }).output;
|
||||
hash = unsignedTx.hashForWitnessV0(
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import { Psbt as PsbtBase } from 'bip174';
|
||||
import { PsbtInput } from 'bip174/src/lib/interfaces';
|
||||
import { checkForInput } from 'bip174/src/lib/utils';
|
||||
import * as classify from './classify';
|
||||
import { Signer } from './ecpair';
|
||||
import { Network } from './networks';
|
||||
import * as payments from './payments';
|
||||
import * as bscript from './script';
|
||||
import { Transaction } from './transaction';
|
||||
|
@ -31,20 +35,73 @@ const checkWitnessScript = scriptCheckerFactory(
|
|||
'Witness script',
|
||||
);
|
||||
|
||||
const isP2WPKH = (script: Buffer): boolean => {
|
||||
const isPayment = (script: Buffer, payment: any): boolean => {
|
||||
try {
|
||||
payments.p2wpkh({ output: script });
|
||||
payment({ output: script });
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
function getScriptFromInput(
|
||||
inputIndex: number,
|
||||
input: PsbtInput,
|
||||
_unsignedTx: Buffer,
|
||||
): Buffer | undefined {
|
||||
let script: Buffer;
|
||||
if (input.nonWitnessUtxo) {
|
||||
if (input.redeemScript) {
|
||||
script = input.redeemScript;
|
||||
} else {
|
||||
const unsignedTx = Transaction.fromBuffer(_unsignedTx);
|
||||
const nonWitnessUtxoTx = Transaction.fromBuffer(input.nonWitnessUtxo);
|
||||
const prevoutIndex = unsignedTx.ins[inputIndex].index;
|
||||
script = nonWitnessUtxoTx.outs[prevoutIndex].script;
|
||||
}
|
||||
} else if (input.witnessUtxo) {
|
||||
if (input.witnessScript) {
|
||||
script = input.witnessScript;
|
||||
} else if (input.redeemScript) {
|
||||
script = payments.p2pkh({ hash: input.redeemScript.slice(2) }).output!;
|
||||
} else {
|
||||
script = payments.p2pkh({ hash: input.witnessUtxo.script.slice(2) })
|
||||
.output!;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
||||
export class Psbt extends PsbtBase {
|
||||
constructor() {
|
||||
constructor(public network?: Network) {
|
||||
super();
|
||||
}
|
||||
|
||||
canFinalize(inputIndex: number): boolean {
|
||||
const input = checkForInput(this.inputs, inputIndex);
|
||||
const script = getScriptFromInput(
|
||||
inputIndex,
|
||||
input,
|
||||
this.globalMap.unsignedTx!,
|
||||
);
|
||||
if (!script) return false;
|
||||
const scriptType = classify.output(script);
|
||||
switch (scriptType) {
|
||||
case 'pubkey':
|
||||
return false;
|
||||
case 'pubkeyhash':
|
||||
return false;
|
||||
case 'multisig':
|
||||
return false;
|
||||
case 'witnesspubkeyhash':
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
signInput(inputIndex: number, keyPair: Signer): Psbt {
|
||||
// TODO: Implement BIP174 pre-sign checks:
|
||||
// https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#signer
|
||||
|
@ -121,7 +178,7 @@ export class Psbt extends PsbtBase {
|
|||
} else {
|
||||
script = input.witnessUtxo.script;
|
||||
}
|
||||
if (isP2WPKH(script)) {
|
||||
if (isPayment(script, payments.p2wpkh)) {
|
||||
// P2WPKH uses the P2PKH template for prevoutScript when signing
|
||||
const signingScript = payments.p2pkh({ hash: script.slice(2) }).output!;
|
||||
hash = unsignedTx.hashForWitnessV0(
|
||||
|
|
5
types/psbt.d.ts
vendored
5
types/psbt.d.ts
vendored
|
@ -1,6 +1,9 @@
|
|||
import { Psbt as PsbtBase } from 'bip174';
|
||||
import { Signer } from './ecpair';
|
||||
import { Network } from './networks';
|
||||
export declare class Psbt extends PsbtBase {
|
||||
constructor();
|
||||
network?: Network | undefined;
|
||||
constructor(network?: Network | undefined);
|
||||
canFinalize(inputIndex: number): boolean;
|
||||
signInput(inputIndex: number, keyPair: Signer): Psbt;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue