Typical Transaction (1 input, 2 outputs) - Native Segwit P2WPKH

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

Let’s create a typical P2WPKH transaction, spending 1 P2WPKH UTXO and creating 2 new P2WPKH UTXOs, one for the actual payment and one for the change.

Create a UTXO to spend from

Send 1 BTC to alice_1 native Segwit P2WPKH address in order to create a P2WPKH UTXO.
sendtoaddress bcrt1qlwyzpu67l7s9gwv4gzuv4psypkxa4fx4ggs05g 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

Creating the transaction

Now let’s spend the 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
Create a bitcoinJS key pair object for alice_1, the owner of our new UTXO, and the only one capable of spending it.
const keyPairAlice1 = bitcoin.ECPair.fromWIF(alice[1].wif, network)

In order to create our input we will have to provide the previous output script. We can get it by inspecting the funding transaction at vout  scriptPubKey  hex.

We can also regenerates the output script, a versioned witness program.
const p2wpkhAlice1 = bitcoin.payments.p2wpkh({pubkey: keyPairAlice1.publicKey, network})
console.log('Previous output script:')

The script is composed as follow: 00 version + PUSHBYTES_14 + public key hash (witness program)

The HASH160 of the public key should match the 20-bytes witness program in the previous output script (the segwit UTXO we are spending).

$ bx bitcoin160 03745c9aceb84dcdeddf2c3cdc1edb0b0b5af2f9bf85612d73fa6394758eaee35d


bitcoin.crypto.hash160(Buffer.from('03745c9aceb84dcdeddf2c3cdc1edb0b0b5af2f9bf85612d73fa6394758eaee35d', 'hex')).toString('hex')
Create a PSBT by filling TX_ID and TX_OUT.
const psbt = new bitcoin.Psbt({network})
    hash: 'TX_ID',
    index: TX_VOUT,
    witnessUtxo: {
      script: Buffer.from('0014' + alice[1].pubKeyHash, 'hex'),
      value: 1e8, (1)
    address: bob[1].p2wpkh,
    value: 5e7,
  }) (2)
    address: alice[1].p2wpkh,
    value: 499e5,
  }) (3)
1 In a Segwit transaction we need to pass the value of the previous transaction which will be part of the message to be signed
2 First output locking 0.5 btc to bob_1 P2WPKH recipient address
3 Second output locking 0.499 btc to alice’s change address. Alice uses the same address for simplicity but an other one would offer better privacy

Let’s calculate our mining fee, subtracting the outputs from the inputs.
100 000 000 - (50 000 000 + 49 900 000) = 100 000 100 000 satoshis, which is equal to 0,001 BTC.

Alice_1 signs the input and validates the signature
psbt.signInput(0, keyPairAlice1)
We don’t have to specify any redeem or witness scripts here, since we are spending a native segwit UTXO. However we still need to sign the input value.
Finalize the PSBT.
Finally we can extract the transaction and get the raw hex serialization.
console.log('Transaction hexadecimal:')
Inspect the raw transaction, check that everything is correct.
decoderawtransaction TX_HEX

Broadcasting the transaction

It’s time to broadcast the transaction via Bitcoin Core CLI.
sendrawtransaction TX_HEX

sendrawtransaction returns the transaction ID, with which you can inspect your transaction again.

getrawtransaction TX_ID true
Don’t forget the second argument. If false, it returns the hex string, otherwise it returns a detailed json object.


In the vin section we note that scriptSig is empty and that we have an additional txinwitness field which contains Alice signature and public key. The semantics of P2WPKH is the same as the semantics of P2PKH, except that the signature is not placed at the same location as before.

In the vout section we have two witness_v0_keyhash outputs, which is the code name for native Segwit.