Runes Token Development (Bitcoin)
Before Runes, there was confusion: BRC-20 ran on top of Ordinals, creating an inscription for every transfer, cluttering the mempool with junk transactions. Casey Rodarmor, creator of Ordinals, designed Runes as a clean-room solution for fungible tokens on Bitcoin — without unnecessary data, using existing Bitcoin primitives. Runes solve the token scaling problem: each BRC-20 transaction produces unwanted inscriptions, increasing the blockchain size. Runes use UTXO and OP_RETURN, making them 10x more compact. In this article, we'll dive into the architecture, etching, transfer, and indexing of Runes, along with real code examples. You'll learn how to avoid common pitfalls, such as losing tokens due to pointer logic, and how to set up an indexer properly. Our experience: 5+ years in blockchain development, 15+ projects on Bitcoin and EVM. We guarantee protocol compliance and no losses due to pointer logic. Contact us for a consultation — we assess complexity and timelines within one day.
How Does the Runes Protocol Work?
Runes does not require changes to the Bitcoin consensus. The protocol lives in OP_RETURN — data is not stored in the UTXO set, so the blockchain doesn't get bloated (unlike BRC-20, which stores state in satoshis).
Key concepts:
- Runestone — the protocol message inside OP_RETURN. Contains etching, mint, transfer, and edicts.
- UTXO as balance carrier — Runes balances are stored not in a global mapping (like ERC-20), but in specific UTXOs. If you hold 1000 RUNE, you have a UTXO with an attached balance.
- Rune ID —
{block_height}:{tx_index}of the etching transaction. For example, the first Rune has ID 840000:3. - Spacers — visual separators in the name (dots), e.g., UNCOMMON•GOODS.
How to Create a Rune (Etching)?
Etching is a transaction with a Runestone in OP_RETURN declaring a new Rune.
Etching parameters: divisibility (0–38, analogous to decimals in ERC-20), symbol (Unicode character for display), premine (amount of tokens for the etcher immediately), terms (conditions for open mint, if allowed) — amount, cap, height, offset, turbo (compatibility flag for future versions).
The Runestone data structure is encoded using varint encoding (LEB128) — a compact variable-length integer representation.
Practical Implementation via ord CLI
# Install ord (official client)
cargo install ord
# Synchronize with Bitcoin node (or via RPC to external)
ord --bitcoin-rpc-url http://user:pass@localhost:8332 index
# Create wallet
ord wallet create
# Etch a new Rune
ord wallet etch \
--rune "MYTOKEN•NAME" \
--divisibility 8 \
--symbol "M" \
--supply 21000000 \
--premine 21000000 \
--fee-rate 20
# Mint (if open mint is enabled)
ord wallet mint \
--rune "MYTOKEN•NAME" \
--fee-rate 20
Via Library (JavaScript/TypeScript)
For integration into an application, use the runestone npm package or work directly with bitcoinjs-lib:
import { Runestone, Etching, Terms, RuneId } from "runestone-lib";
import * as bitcoin from "bitcoinjs-lib";
function buildEtchingTransaction(
utxo: UTXO,
runeName: string,
divisibility: number,
supply: bigint,
feeRate: number
): bitcoin.Transaction {
const runestone = new Runestone({
etching: new Etching({
rune: Rune.fromString(runeName),
divisibility,
symbol: "T",
premine: supply,
turbo: true,
}),
edicts: [{
id: new RuneId(0n, 0n), // 0:0 = itself during etching
amount: supply,
output: 1n, // output index for receiving premine
}],
});
const psbt = new bitcoin.Psbt({ network: bitcoin.networks.bitcoin });
// Input: funded UTXO to pay fees
psbt.addInput({
hash: utxo.txid,
index: utxo.vout,
witnessUtxo: { script: utxo.scriptPubKey, value: utxo.value },
});
// Output 0: OP_RETURN with Runestone
psbt.addOutput({
script: bitcoin.script.compile([
bitcoin.opcodes.OP_RETURN,
Buffer.from("52554e45", "hex"), // RUNE magic bytes
runestone.encipher(),
]),
value: 0,
});
// Output 1: recipient of premine (must be above dust)
psbt.addOutput({
address: recipientAddress,
value: 546, // dust limit for P2WPKH
});
// Output 2: change
psbt.addOutput({ address: changeAddress, value: changeAmount });
return psbt;
}
Technical Details of Runestone
Runestone is a binary format that can contain etching, mint, transfer, and edicts. The etching field defines the attributes of the new token: name (up to 26 characters with separators), divisibility (0-38), symbol (single Unicode), premine, and open mint conditions. Edicts are transfer instructions, each containing a Rune id, amount, and output number. The cost of etching on mainnet is approximately $2–5 per transaction at current fees.Transferring Runes (Edicts)
Transferring Runes is a transaction with a Runestone containing edicts. Each edict specifies: which Rune, how many, to which output.
Important protocol rule: if the Rune balance of an input UTXO is not fully covered by edicts, the remainder automatically goes to the first non-OP_RETURN output (pointer). No explicit pointer means the first output. This differs from EVM, where unspent funds remain with the sender.
Example: you have a UTXO with 1000 RUNE. Transaction with edict: send 300 RUNE → output 2. Automatically: 700 RUNE → output 1 (default pointer). If output 1 is a burn address, you accidentally burn 700 RUNE. This is the main cause of token loss — misunderstanding pointer logic. When developing a Runes wallet, you must explicitly configure the pointer output to the user's change address.
Indexing Runes: Options and Practice
Runes do not have a standard RPC API in Bitcoin Core — a separate indexer is required. Compare options:
| Indexer | Type | Advantages | Disadvantages |
|---|---|---|---|
| ord | Self-hosted | Full control, open source | Requires Bitcoin node + ~100 GB SSD |
| Hiro Ordinals API | Hosted | No node needed, simple REST | Paid, risk of unavailability |
| Unisat API | Hosted | Runes support, free tier | Rate limit for high loads |
For production, we use our own ord indexer with replication — guaranteeing availability and speed. Up to 40% savings compared to hosted solutions.
How Runes Differs from BRC-20
| Characteristic | Runes | BRC-20 |
|---|---|---|
| Data model | UTXO with attached balance | Inscription with JSON state |
| Transaction size | ~100–200 bytes | ~400–1000 bytes |
| Node requirements | Full Bitcoin node + ord | Full Bitcoin node + Ordinals |
| Flexibility | Only transfer/burn | Only transfer/burn |
| Maturity | Active development, launched recently | Stable but buggy |
What's Included in Our Runes Token Development
- Tokenomics and protocol parameter analysis
- Etching, mint, and transfer logic
- Wallet integration (list of Runes-supporting wallets)
- Development of an indexing API (ord + custom endpoints)
- UI for mint/transfer (optional)
- Testnet and mainnet testing
- Documentation and team training
- One month of technical support after launch
Limitations of Runes (What to Know in Advance)
Runes are not smart contracts. No conditional transfers, staking, or DEX without a separate solution. All logic familiar from Solidity is impossible on-chain. Only creation, transfer, and burn are available.
For DeFi on top of Runes, you need off-chain matching (centralized orderbook) or a separate L2 with verification via Bitcoin SPV. Comparison with ERC-20: EVM tokens win in flexibility, but Runes provide native Bitcoin security and audience.
Development timeline: etching and basic wallet — 1–2 weeks. Full integration with indexer and marketplace — 6–10 weeks. Pricing is determined individually after requirements audit. Get a consultation for your project — we assess complexity and propose the optimal solution.
Our experience: 5+ years in blockchain development, 15+ projects on Bitcoin and EVM. We guarantee protocol compliance and no losses due to pointer logic.







