bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.
MIT License
5.71k stars 2.11k forks source link

How to sign Psbt with P2WSH(P2MS) Script? #2126

Closed renz-leverfi closed 4 months ago

renz-leverfi commented 4 months ago

Please help. I have a utxo with P2WSH(P2MS) script, I am having trouble to sign the transaction together while appending a signature of another party

In my understanding of P2WSH, it must have the following structure (assumed the order of signature is correct);

[
  00
  mySignature
  anotherPartySignature
  witnessScript
]

Here is the simplest form of how I tried signing the transaction

const txHex: string
const otherPartyPubkey: Buffer // compressed pubkey
const otherPartySig: Buffer // is a finalized serialized der encoded sig
const p2ms_pubkey: Buffer
const p2wsh_wp2ms_pubkey: Buffer

const tx = Transaction.fromHex(txHex)

const inputs = tx.ins.map(input => {
  return {
    hash: input.hash,
    index: input.index,
    sequence: input.sequence,
    witnessUtxo: {
      value: 1000,
      script: p2wsh_wp2ms_pubkey,
    },
    witnessScript: p2ms_pubkey,

    // This is how I thought the way to append a signature, but is incorrect
    // partialSig: [{
    //   pubkey: otherPartyPubkey,
    //   signature: otherPartySig,
    // }],
    // sighashType: 0x01,
  }
})

const psbt = new Psbt()
  .setVersion(tx.version)
  .setLocktime(tx.locktime)
  .addInputs(inputs)
  .addOutputs(tx.outs)

psbt.signInput(0, signer, 0x01)
psbt.finalizeInput(0)

I put p2ms on witnessScript; because of this checker function

https://github.com/bitcoinjs/bitcoinjs-lib/blob/8edc5e831ec8a2581059ea908a43b704f7cd962d/ts_src/psbt.ts#L1433-L1453

But this become a problem when finalizing the inputs

https://github.com/bitcoinjs/bitcoinjs-lib/blob/8edc5e831ec8a2581059ea908a43b704f7cd962d/ts_src/psbt.ts#L1509-L1531

What to do here?

UTXO with prevout of P2WSH(P2MS)

https://mempool.space/testnet/tx/7ac6dde5ffda902d1741e9ffc3cd20790240da077cb7d302c25c662c26bf96aa

Here are my questions

  1. Is it possible to append another party's signature to the Witness Field when finalizing the input? How?
  2. I am totally confuse on what to use between witnessUtxo and nonWitnessUtxo because the witnessScript is considered a non-segwit script
  3. what should be the content of witnessScript, witnessUtxo.script?
renz-leverfi commented 4 months ago

Fixed it, I just insert the other partialSig later after signing, here is how I did it;

const inputs = tx.ins.map(input => {
  return {
    hash: input.hash,
    index: input.index,
    sequence: input.sequence,
    witnessUtxo: {
      value: 1000,
      script: p2wsh_wp2ms_pubkey,
    },
    witnessScript: p2ms_pubkey,
  }
})

const psbt = new Psbt()
  .setVersion(tx.version)
  .setLocktime(tx.locktime)
  .addInputs(inputs)
  .addOutputs(tx.outs)

psbt.signInput(0, signer, 0x01)

psbt.updateInput(0, {
  partialSig: [{
    pubkey: otherPartyPubkey,
    signature: otherPartySig,
  }]
})

psbt.finalizeAllInputs()

It feels like a hack, but it works, if there is proper way, please let me know.