Bitcoinjs-lib: Signing a P2WSH with transaction builder

Created on 21 Aug 2017  路  10Comments  路  Source: bitcoinjs/bitcoinjs-lib

Hello.

I want to be able to set scriptsig/witness of my transaction below:


var bitcoin = require('bitcoinjs-lib')
var ops = bitcoin.opcodes

//Create P2SH Address 
var witnessScript = bitcoin.script.compile([
    ops.OP_ADD,
    ops.OP_13,
    ops.OP_EQUALVERIFY
])

var witnessScriptHash = bitcoin.crypto.sha256(witnessScript)
var redeemScript = bitcoin.script.witnessScriptHash.output.encode(witnessScriptHash)
var redeemScriptHash = bitcoin.crypto.hash160(redeemScript)
var scriptPubKey = bitcoin.script.scriptHash.output.encode(redeemScriptHash)
var P2SHaddress = bitcoin.address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet)

// Attempt to spend the coins sent to the wallet above
var txb = new bitcoin.Transaction(bitcoin.networks.testnet)
var XwitnessScript = bitcoin.script.compile([
    ops.OP_4,
    ops.OP_9,
])

How to set scriptsig/witness?

how to / question / docs

Most helpful comment

Here's an example:

var bitcoin = require('bitcoinjs-lib')
var ops = bitcoin.opcodes

//Create P2SH Address 
var witnessScript = bitcoin.script.compile([
    ops.OP_ADD,
    ops.OP_7,
    ops.OP_EQUAL
])

var witnessScriptHash = bitcoin.crypto.sha256(witnessScript)
var redeemScript = bitcoin.script.witnessScriptHash.output.encode(witnessScriptHash)
var redeemScriptHash = bitcoin.crypto.hash160(redeemScript)
var scriptPubKey = bitcoin.script.scriptHash.output.encode(redeemScriptHash)
var P2SHaddress = bitcoin.address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet)

//console.log(P2SHaddress)

// Queried the utxo I sent:
// [{"address":"2NFCQZeVoMTjKUc3nxrx4w72xHnb6DJu6Jy",
// "txid":"218d042331071189a785624d5be2a6dc315484e7bd2468235e18e488211d2bee",
// "vout":0,
// "scriptPubKey":"a914f0ca58dc8e539421a3cb4a9c22c059973075287c87",
// "amount":0.001,
// "satoshis":100000,
// "confirmations":0,
// "ts":1503328519}]

// Attempt to spend the coins sent to the wallet above
var tx = new bitcoin.Transaction(bitcoin.networks.testnet)

tx.ins.push({
    hash: Buffer.from('218d042331071189a785624d5be2a6dc315484e7bd2468235e18e488211d2bee','hex').reverse(),
    index: 0,
    script: bitcoin.script.compile([redeemScript]), // This compile will add the PUSHDATA byte to treat the redeemScript as data
    sequence: 0xffffffff,
    witness: [
        Buffer.from('04','hex'), // witnesses need to be PUSHDATA so push 04 byte for the number 4 (don't use OP_4)
        Buffer.from('03','hex'),
        witnessScript
    ]
})

tx.outs.push({
    script: scriptPubKey, // sent back to itself because I'm lazy.
    value: 99000
})

console.log(tx.toHex())

// 01000000
// 00
// 01
// 01 // input count
// ee2b1d2188e4185e236824bde7845431dca6e25b4d6285a78911073123048d21
// 00000000
// 23
//   22
//     00 20
//           f5ac8d00e92b7131aae203ea7c8836842ec5fbd63f6c99c3ec1224d8adbd1075
// ffffffff
// 01 // output count
// b882010000000000
// 17
//   a9 14
//         f0ca58dc8e539421a3cb4a9c22c059973075287c
//            87
// 03 // witness count for input #1
// 01
//   04
// 01
//   03
// 03
//   93 57 87
// 00000000

// txid: a4c89e0ffb84d06a1e62f0f9f0f5974db250878caa1f71f9992a1f865b8ff2fa

All 10 comments

tx.ins.push({
  hash: readSlice(32),
  index: readUInt32(),
  script: readVarSlice(),
  sequence: readUInt32(),
  witness: EMPTY_WITNESS
})

This is a part of deserializing, so hash and script are buffers (hash is the reversed bytes of the txid string you're used to)

The witness is an array of buffers.

Then just push an output or two. Then output to hex and broadcast.

Place a PUSH_DATA + redeemScript in the script

Place your OP codes as Buffers (or numbers???) in the array witness.

Here's an example:

var bitcoin = require('bitcoinjs-lib')
var ops = bitcoin.opcodes

//Create P2SH Address 
var witnessScript = bitcoin.script.compile([
    ops.OP_ADD,
    ops.OP_7,
    ops.OP_EQUAL
])

var witnessScriptHash = bitcoin.crypto.sha256(witnessScript)
var redeemScript = bitcoin.script.witnessScriptHash.output.encode(witnessScriptHash)
var redeemScriptHash = bitcoin.crypto.hash160(redeemScript)
var scriptPubKey = bitcoin.script.scriptHash.output.encode(redeemScriptHash)
var P2SHaddress = bitcoin.address.fromOutputScript(scriptPubKey, bitcoin.networks.testnet)

//console.log(P2SHaddress)

// Queried the utxo I sent:
// [{"address":"2NFCQZeVoMTjKUc3nxrx4w72xHnb6DJu6Jy",
// "txid":"218d042331071189a785624d5be2a6dc315484e7bd2468235e18e488211d2bee",
// "vout":0,
// "scriptPubKey":"a914f0ca58dc8e539421a3cb4a9c22c059973075287c87",
// "amount":0.001,
// "satoshis":100000,
// "confirmations":0,
// "ts":1503328519}]

// Attempt to spend the coins sent to the wallet above
var tx = new bitcoin.Transaction(bitcoin.networks.testnet)

tx.ins.push({
    hash: Buffer.from('218d042331071189a785624d5be2a6dc315484e7bd2468235e18e488211d2bee','hex').reverse(),
    index: 0,
    script: bitcoin.script.compile([redeemScript]), // This compile will add the PUSHDATA byte to treat the redeemScript as data
    sequence: 0xffffffff,
    witness: [
        Buffer.from('04','hex'), // witnesses need to be PUSHDATA so push 04 byte for the number 4 (don't use OP_4)
        Buffer.from('03','hex'),
        witnessScript
    ]
})

tx.outs.push({
    script: scriptPubKey, // sent back to itself because I'm lazy.
    value: 99000
})

console.log(tx.toHex())

// 01000000
// 00
// 01
// 01 // input count
// ee2b1d2188e4185e236824bde7845431dca6e25b4d6285a78911073123048d21
// 00000000
// 23
//   22
//     00 20
//           f5ac8d00e92b7131aae203ea7c8836842ec5fbd63f6c99c3ec1224d8adbd1075
// ffffffff
// 01 // output count
// b882010000000000
// 17
//   a9 14
//         f0ca58dc8e539421a3cb4a9c22c059973075287c
//            87
// 03 // witness count for input #1
// 01
//   04
// 01
//   03
// 03
//   93 57 87
// 00000000

// txid: a4c89e0ffb84d06a1e62f0f9f0f5974db250878caa1f71f9992a1f865b8ff2fa

I think this is example worthy :) Be great if signrawtransaction accepts and returns true for this (a tiny snippet to test the above tx?)

var tx = new bitcoin.Transaction(bitcoin.networks.testnet)

The network parameter is for bitcoin.TransactionBuilder, not bitcoin.Transaction.
bitcoin.Transaction has no constructor parameters.

Nice example though :+1:

Thank you so much. worked perfectly :)

PRs accepted to add this as an example, otherwise, separate issue for tracking? :)

Can we build transaction for litecoin the same way?

yes

Was this page helpful?
0 / 5 - 0 ratings

Related issues

namnv04 picture namnv04  路  3Comments

rbndg picture rbndg  路  3Comments

dcousens picture dcousens  路  3Comments

yakitorifoodie picture yakitorifoodie  路  3Comments

panpan2 picture panpan2  路  3Comments