|
|
@ -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( |
|
|
|