Spend a Nested Segwit P2SH-P2WPKH UTXO

To follow along this tutorial

  • Clone the Github repository

  • cd code

  • npm install or yarn install

  • Execute the transaction code by typing node tx_filename.js

  • Alternatively you can enter the commands step-by-step by cd into ./code then type node in a terminal to open the Node.js REPL

  • Open the Bitcoin Core GUI console or use bitcoin-cli for the Bitcoin Core commands

  • Use bx aka Libbitcoin-explorer as a handy complement

Learn more about P2SH here

Let’s spend a P2SH-P2WPKH output (embedded Segwit) and create a new P2WPKH output.

Create a UTXO to spend from

Import libraries, test wallets and set the network
const bitcoin = require('bitcoinjs-lib')
const { alice, bob } = require('./wallets.json')
const network = bitcoin.networks.regtest
Send 1 BTC to alice_1 embedded Segwit P2SH-P2WPKH address in order to create a NP2WPKH (or P2SH-P2WPKH) UTXO (which is in fact a regular

P2SH UTXO).

sendtoaddress 2MzFvFvnhFskGnVQpUr1ZPr4wYWLwf211s6 1
Get the output index so that we have the outpoint (txid / vout).
gettransaction TX_ID
Find the output index (or vout) under details  vout.

You can note that the UTXO is of type scripthash, which means that it is a P2SH UTXO.

Creating the transaction

Now let’s spend the P2SH-P2WPKH UTXO with BitcoinJS.

Prepare the redeem script.
const keyPairAlice1 = bitcoin.ECPair.fromWIF(alice[1].wif, network) (1)
const p2wpkhAlice1 = bitcoin.payments.p2wpkh({pubkey: keyPairAlice1.publicKey, network}) (2)
const p2shAlice1 = bitcoin.payments.p2sh({redeem: p2wpkhAlice1, network}) (3)
console.log('Redeem script')
console.log(p2shAlice1.redeem.output.toString('hex'))
1 Create a bitcoinJS keypair object for the spender alice_1
2 Create a P2WPKH payment object
3 Pass it to the P2SH payment method

The redeem script is composed of a 00 version byte and a 20 bytes witness program, HASH160 of alice_1 public key. It is the same as the previous output script p2wpkhAlice1.output that we pass to txb.addInput() in Spend a Native Segwit P2WPKH UTXO.

Create a keypair and a P2WPKH address for the recipient bob_1.
const keyPairBob1 = bitcoin.ECPair.fromWIF(bob[1].wif, network)
const p2wpkhBob1 = bitcoin.payments.p2wpkh({pubkey: keyPairBob1.publicKey, network})
console.log('P2WPKH address')
console.log(p2wpkhBob1.address)
Create a BitcoinJS transaction builder object.
const txb = new bitcoin.TransactionBuilder(network)
Create the input.
txb.addInput('TX_ID', TX_VOUT)
Create the output, locking 0.999btc to bob_1 P2WPKH.
txb.addOutput(p2wpkhBob1.address, 999e5)
Alice_1 signs.
// txb.sign(index, keyPair, redeemScript, sign.hashType, value, witnessScript)
txb.sign(0, keyPairAlice1, p2shAlice1.redeem.output, null, 1e8, null)
Finally we can build the transaction and get the raw hex serialization.
const tx = txb.build()
console.log('Transaction hexadecimal:')
console.log(tx.toHex())
Inspect the raw transaction with Bitcoin Core CLI, check that everything is correct.
decoderawtransaction TX_HEX

Broadcasting the transaction

It’s time to broadcast the transaction.
sendrawtransaction TX_HEX
Inspect the transaction.
getrawtransaction TX_ID true

Observations

In the vin section the scriptSig is the redeem script. When passed through HASH160 it should match the hash contained in the script of the P2SH UTXO we are spending.

$ bx bitcoin 160 0014fb8820f35effa054399540b8ca86040d8ddaa4d5
4cea7ef76a4423240d5f06d96868726f57bd7d30

The signature in txinwitness is then verified against alice_1 public key.

In the vout section we have one witness_v0_keyhash UTXO, bob_1 P2WPKH.