Typical Transaction (1 input, 2 outputs) - Native Segwit P2WPKH
To follow along this tutorial
|
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
const bitcoin = require('bitcoinjs-lib')
const { alice, bob } = require('./wallets.json')
const network = bitcoin.networks.regtest
sendtoaddress bcrt1qlwyzpu67l7s9gwv4gzuv4psypkxa4fx4ggs05g 1
gettransaction TX_ID
Find the output index (or vout) under |
Creating the transaction
Now let’s spend the UTXO with BitcoinJS.
const keyPairAlice1 = bitcoin.ECPair.fromWIF(alice[1].wif, network)
const p2wpkhAlice1 = bitcoin.payments.p2wpkh({pubkey: keyPairAlice1.publicKey, network})
const keyPairBob1 = bitcoin.ECPair.fromWIF(bob[1].wif, network)
const p2wpkhBob1 = bitcoin.payments.p2wpkh({pubkey: keyPairBob1.publicKey, network})
console.log('P2PKH address:')
console.log(p2pkhBob1.address)
const txb = new bitcoin.TransactionBuilder(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
.const p2wpkhAlice1 = bitcoin.payments.p2wpkh({pubkey: keyPairAlice1.publicKey, network})
console.log('Previous output script:')
console.log(p2wpkhAlice1.output.toString('hex'))
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
fb8820f35effa054399540b8ca86040d8ddaa4d5
or
bitcoin.crypto.hash160(Buffer.from('03745c9aceb84dcdeddf2c3cdc1edb0b0b5af2f9bf85612d73fa6394758eaee35d', 'hex')).toString('hex')
// txb.addInput(prevTxId, prevOutIndex, sequence, prevOutScript)
txb.addInput('TX_ID', TX_VOUT, null, p2wpkhAlice1.output)
Add a first output locking 0.5 btc to bob_1 P2WPKH recipient address.
Add a second output locking 0.499 btc to alice’s change address.
txb.addOutput(p2wpkhBob1.address, 5e7)
txb.addOutput(p2wpkhAlice1.address, 499e5) (1)
1 | Here we use 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.
// txb.sign(index, keyPair, redeemScript, sign.hashType, value, witnessScript)
txb.sign(0, keyPairAlice1, null, null, 1e8, null)
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. |
const tx = txb.build()
console.log('Transaction hexadecimal:')
console.log(tx.toHex())
decoderawtransaction TX_HEX
Broadcasting the transaction
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. |
Observations
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.