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.

Creating a UTXO to spend

Send 1 BTC to alice_1 embedded Segwit P2SH-P2WPKH address in order to create a NP2WPKH (or P2SH-P2WPKH) 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.

Import libraries, test wallets and set the network
const bitcoin = require('bitcoinjs-lib')
const { alice, bob } = require('./wallets.json')
const network = bitcoin.networks.regtest
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)
const redeemScript = p2shAlice1.redeem.output.toString('hex')
console.log('Redeem script:')
console.log(redeemScript)
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, which is the HASH160 of alice_1 public key.

Create a PSBT by filling TX_ID and TX_OUT.
const psbt = new bitcoin.Psbt({network})
  .addInput({
    hash: 'TX_ID',
    index: TX_VOUT,
    witnessUtxo: {
      script: Buffer.from('a914' +
        bitcoin.crypto.hash160(Buffer.from('0014' + alice[1].pubKeyHash, 'hex')).toString('hex') +
        '87', 'hex'), (1)
      value: 1e8,
    },
    redeemScript: Buffer.from(redeemScript, 'hex')
  })
  .addOutput({
    address: bob[1].p2wpkh,
    value: 999e5,
  }) (2)
1 The scriptPubKey is the Hash160 of the redeem script, inside a standard P2SH template
2 Lock 0.999btc to bob_1 P2WPKH
Alice_1 signs the input and validates the signature
psbt.signInput(0, keyPairAlice1)
psbt.validateSignaturesOfInput(0)
Finalize the PSBT.
psbt.finalizeAllInputs()
Finally we can extract the transaction and get the raw hex serialization.
console.log('Transaction hexadecimal:')
console.log(psbt.extractTransaction().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.