OP_RETURN
The simplest way to store data on the Bitcoin blockchain. Clean, lightweight, and readable by anyone.
What is OP_RETURN?
OP_RETURN is a Bitcoin script opcode that marks a transaction output as provably unspendable. Any data placed after the OP_RETURN opcode is embedded directly in the transaction and stored permanently in the blockchain history.
Because the output is unspendable, Bitcoin nodes don’t need to track it in the UTXO set (the database of unspent coins). This makes OP_RETURN the “cleanest” way to store data on Bitcoin — it doesn’t bloat the set that every node must keep in memory.
Transaction Structure
An OP_RETURN engraving transaction has this structure:
Input:
- Server wallet UTXO (P2WPKH)
Outputs:
1. OP_RETURN <your message as UTF-8 bytes> (0 sats, data carrier)
2. Recipient address (7,800 sats dust, if specified)
3. Change back to server wallet (remaining balance)The OP_RETURN output carries zero value — it exists solely to hold your data. The Bitcoin protocol limits OP_RETURN data to 80 bytes, which is why EternalChain caps inscriptions at 80 characters.
Script Encoding
The output script is built byte-by-byte:
// For messages up to 75 bytes:
Script = [0x6a] [length_byte] [data_bytes...]
OP_RETURN push N your message
// For messages 76-80 bytes:
Script = [0x6a] [0x4c] [length_byte] [data_bytes...]
OP_RETURN OP_PUSHDATA1 push N your message
Example: "Hello" (5 bytes)
Hex: 6a 05 48 65 6c 6c 6f
^ ^ ^^^^^^^^^^^^^^^^^^
| | "Hello" in UTF-8
| push 5 bytes
OP_RETURNDecoding an OP_RETURN Inscription
To read an OP_RETURN inscription from a transaction:
// 1. Fetch the transaction from mempool.space
const res = await fetch("https://mempool.space/api/tx/<txid>");
const tx = await res.json();
// 2. Find the OP_RETURN output
const opReturn = tx.vout.find(
(o) => o.scriptpubkey.startsWith("6a")
);
// 3. Parse the push data
const script = opReturn.scriptpubkey;
const pushByte = parseInt(script.slice(2, 4), 16);
let dataHex;
if (pushByte === 0x4c) {
// OP_PUSHDATA1 — next byte is length
const len = parseInt(script.slice(4, 6), 16);
dataHex = script.slice(6, 6 + len * 2);
} else {
// Direct push — pushByte is the length
dataHex = script.slice(4, 4 + pushByte * 2);
}
// 4. Decode UTF-8
const bytes = new Uint8Array(
dataHex.match(/.{2}/g).map((b) => parseInt(b, 16))
);
const message = new TextDecoder().decode(bytes);
console.log(message); // Your inscriptionCost Breakdown
OP_RETURN transactions are lightweight. The operator cost depends on two factors:
Estimated vsize (80-char message, with recipient):
Overhead: 11 vB
P2WPKH input: 68 vB
OP_RETURN output: 92 vB (9 header + 83 script)
Recipient output: 31 vB
Change output: 31 vB
─────────────────────────
Total: 233 vB
At 10 sat/vB fee rate:
Miner fee: 2,330 sats
Recipient: 7,800 sats (dust)
Total cost: 10,130 sats (~$6.58 at $65k BTC)