Embedding Data with OP_RETURN
To follow along this tutorial and enter the commands step-by-step
- Type
node
in a terminal aftercd
into./code
for a Javascript prompt- Open the Bitcoin Core GUI console or use
bitcoin-cli
for the Bitcoin Core commands- Use
bx
akaLibbitcoin-explorer
as a handy complement
Let's store for eternity some data on the Bitcoin blockchain using the special OP_RETURN opcode.
It will create a special nulldata
output type.
An output using an OP_RETURN is provably unspendable, so we don't need to lock any BTC in this UTXO.
However, we still need to pay the miner fees, so we will spend BTC from a previous P2WPKH UTXO, create one nulldata
UTXO
and an other one for the change, leaving the difference as mining fees.
For more information about OP_RETURN check out:
Create a UTXO to spend from
Let's create a P2WPKH UTXO to spend from.
Import libraries, test wallet and set the network.
const bitcoin = require('bitcoinjs-lib')
const { alice } = require('./wallets.json')
const network = bitcoin.networks.regtest
Send 1 BTC to Alice_0 P2WPKH address via Bitcoin Core CLI.
$ sendtoaddress bcrt1qlwyzpu67l7s9gwv4gzuv4psypkxa4fx4ggs05g 1
Get the output index so that we have the outpoint (txid / vout).
Find the output index (or vout) under
details > vout
.
$ gettransaction "txid"
Creating the transaction
Now let's create our OP_RETURN P2PKH UTXO.
Create a bitcoinJS key pair object for the spender Alice_0 and a P2WPKH, address that we will use for the change.
const keyPairAlice0 = bitcoin.ECPair.fromWIF(alice[0].wif, network)
const p2wpkhAlice0 = bitcoin.payments.p2wpkh({pubkey: keyPairAlice0.publicKey, network})
Create a BitcoinJS transaction builder object.
const txb = new bitcoin.TransactionBuilder(network)
Fill in the outpoint.
Don't forget the prevTxScript, necessary because we are spending a P2WPKH.
// txb.addInput(prevTx, input.vout, input.sequence, prevTxScript)
txb.addInput('TX_ID', TX_VOUT, null, p2wpkhAlice0.output)
Create an OP_RETURN output with BitcoinJS embed
payment method.
Create a second output to get back the change. 100 000 000 - 100 000(fees) = 99 900 000 sats
An output using an OP_RETURN is provably unspendable. For this reason, the value of an OP_RETURN output
is usually set to 0.
const data = Buffer.from('Programmable money FTW!', 'utf8')
const embed = bitcoin.payments.embed({data: [data]})
txb.addOutput(embed.output, 0)
txb.addOutput(p2wpkhAlice0.address, 99900000)
Don't forget the input value, necessary because we are spending a P2WPKH.
// txb.sign(index, keyPair, redeemScript, sign.hashType, value, witnessScript)
txb.sign(0, keyPairAlice0, null, null, 1e8)
Finally we can build the transaction and get the raw hex serialization.
const tx = txb.build()
console.log('tx.toHex()', tx.toHex())
Inspect the raw transaction with Bitcoin Core CLI, check that everything is correct.
$ decoderawtransaction "hexstring"
Broadcasting the transaction
It's time to broadcast the transaction.
$ sendrawtransaction "hexstring"
Inspect the transaction.
$ getrawtransaction "txid" true
Observations
We note that the OP_RETURN UTXO is marked with the special type nulldata
.
To decode the OP_RETURN data we can use the xxd
library in a terminal which make a hexdump or the reverse.
$ echo 50726f6772616d6d61626c65206d6f6e65792046545721 | xxd -p -r
Comments