Normative specification · version 1.0.0
BRC-20 specification
This document states the BRC-20 payload format and validity rules as one numbered rulebook. The protocol originated with domo's March 2023 experiment; the maintained indexing rules are published by the Layer1 Foundation with OPI as the open reference implementation. This page restates those rules for implementers and marks every Bitcoin Universe-specific indexing decision explicitly in section 8.
Rules are numbered R1 to R24 and are individually linkable (for example #r10). The payload validator and the test vectors cite these rule numbers. An operation that breaks any applicable rule has no effect on the ledger; there are no partial applications except the last-mint remainder rule R14.
1. Carrier and encoding
A BRC-20 operation is the content of one Ordinals inscription:
- The content is committed in a taproot witness using the ord envelope (commit transaction, then reveal transaction) and is tracked to a single satoshi under the Ordinals numbering rules.
- The content type must be
text/plain(any charset parameter) orapplication/json(R2). - The body is one UTF-8 JSON object (R1). Whitespace between tokens is irrelevant. Every protocol value is a JSON string, including all numbers (R3).
{"p":"brc-20","op":"deploy","tick":"ordi","max":"21000000","lim":"1000"}
That single line, inscription number 348020, opened the first BRC-20 ticker. The protocol has no other wire format: no OP_RETURN variant, no binary encoding.
2. Identifiers
- Ticker (
tick) - The asset identifier. Exactly 4 UTF-8 bytes
(R7). The limit counts bytes, not characters:
"ordi"is 4 bytes, and a single 4-byte emoji is also a valid ticker. Comparison is case-insensitive (R8):ordi,ORDI, andOrDiare the same asset. Under the self-issuance extension (section 7), a ticker may instead be exactly 5 bytes. - Inscription ID
<reveal-txid>i<index>, for exampleb61b0172d95e266c18aea0c624db987e971a5d6d4ebc2aaed85da4642d635735i0. Identifies one inscription, and therefore one operation.- Address
- Balance identity is the output script (scriptPubKey) holding the inscribed satoshi (R22). In practice this is an address, usually taproot.
3. Operations
3.1 deploy
Opens the ledger for a new ticker and fixes its economics forever.
| Field | Required | Value | Constraints |
|---|---|---|---|
p | yes | "brc-20" | Exact lowercase string (R4) |
op | yes | "deploy" | Exact lowercase string (R5) |
tick | yes | ticker | 4 UTF-8 bytes; 5 with self_mint (R7) |
max | yes | maximum supply | Positive decimal string, amount grammar (R9, R11) |
lim | no | per-mint limit | Positive, at most max; defaults to max (R9) |
dec | no | decimal places | Integer string 0 to 18; defaults to 18 (R9) |
self_mint | no | "true" | Extension; required for 5-byte tickers (section 7) |
{"p":"brc-20","op":"deploy","tick":"ordi","max":"21000000","lim":"1000"}
3.2 mint
Credits new units to the first owner of the mint inscription.
| Field | Required | Value | Constraints |
|---|---|---|---|
p | yes | "brc-20" | Exact lowercase string (R4) |
op | yes | "mint" | Exact lowercase string (R5) |
tick | yes | ticker | Must match a confirmed deploy (R12) |
amt | yes | amount to mint | Positive, at most lim, decimals within dec (R13) |
{"p":"brc-20","op":"mint","tick":"ordi","amt":"1000"}
3.3 transfer
Moves units in two phases: first inscribe the intent, then spend the inscription (section 4).
| Field | Required | Value | Constraints |
|---|---|---|---|
p | yes | "brc-20" | Exact lowercase string (R4) |
op | yes | "transfer" | Exact lowercase string (R5) |
tick | yes | ticker | Must match a confirmed deploy (R12) |
amt | yes | amount to move | Positive, at most the available balance at confirmation (R16) |
{"p":"brc-20","op":"transfer","tick":"ordi","amt":"100"}
4. Validity rules
Envelope and parsing
- The inscription content MUST parse as exactly one JSON object. Content that is not valid JSON, or that parses to an array, string, number, boolean, or null, is not a BRC-20 operation and is ignored entirely.
- The inscription content type MUST be
text/plain(with or without parameters such as;charset=utf-8) orapplication/json. Other content types are not BRC-20 operations. - Every protocol field value MUST be a JSON string. A JSON number, boolean, or
null in
p,op,tick,max,lim,amt,dec, orself_mintmakes the operation invalid."max": 21000000(unquoted) is the classic mistake. - The
pfield MUST equal"brc-20"exactly: lowercase, with the hyphen. Any other value means the inscription is not a BRC-20 operation. - The
opfield MUST equal"deploy","mint", or"transfer"exactly, in lowercase. - Keys are case-sensitive. Unknown keys are ignored and do not invalidate an otherwise valid operation. A missing required key makes the operation invalid.
Tickers
tickMUST be exactly 4 bytes when encoded as UTF-8. Under the self-issuance extension a deploy with"self_mint": "true"MAY instead use a ticker of exactly 5 UTF-8 bytes, and mints and transfers of such a ticker carry the same 5-byte value. The limit counts bytes, never characters.- Ticker identity is case-insensitive. Indexers MUST compare tickers after lowercasing and SHOULD preserve the deploy's original casing for display.
deploy
maxis required and MUST be positive.lim, when present, MUST be positive and MUST NOT exceedmax; when absent it defaults tomax.dec, when present, MUST be a string of digits representing an integer from 0 through 18; when absent it defaults to 18. Arithmetic is uint-safe: no value may exceed the uint64 maximum, 18446744073709551615.- First is valid. The first valid confirmed deploy of a ticker
owns it. Every later deploy of the same ticker (case-insensitive) is ignored, whatever its
fields say. Deployment economics (
max,lim,dec) are immutable once indexed. - Numeric values use the amount grammar
(0|[1-9][0-9]*)(.[0-9]+)?: base-10, no sign, no exponent, no leading zeros, no lone leading or trailing decimal point, no separators. After trimming trailing zeros, the fractional digits MUST NOT exceed the ticker'sdec.
mint
- A mint is valid only for a ticker whose valid deploy was confirmed in an earlier block, or earlier in the same block by transaction order. Minting an undeployed ticker has no effect.
amtis required, MUST be positive, MUST respect the amount grammar and the ticker'sdec, and MUST NOT exceed the ticker's per-mintlim.- A mint that would push minted supply past
maxis credited only the remaining amount. Once minted supply equalsmax, every further mint is invalid. This remainder rule is the protocol's only partial application. - The minted amount credits the available balance of the first owner of the mint inscription: the address that receives the inscribed satoshi in the reveal transaction.
transfer
- Inscribing a transfer is valid only if
amtis at most the inscribing address's available balance at the moment the transfer inscription is confirmed. A transfer inscription that fails this test is permanently void; a later balance increase never revives it. - A valid transfer inscription immediately moves
amtfrom the owner's available balance to their transferable balance. Overall balance is unchanged; the amount is reserved, exactly once, against that specific inscription. - A transfer inscription is one-use. Only its first spend after the inscription settles it. Any later movement of the same inscription is an ordinary inscription transfer with no BRC-20 effect.
- If the first spend delivers the inscription to a different address, the
sender's overall balance is debited
amtand the recipient's available balance is creditedamt. - If the first spend returns the inscription to the sender, the reservation is
released:
amtmoves back from transferable to available and no ownership changes. - If the first spend consumes the inscription as transaction fee (the inscribed satoshi ends up in the miner's fee claim), the inscription is spent and the amount returns to the sender's available balance. No third party is credited.
Ordering and identity
- Balances attach to output scripts (scriptPubKey). Operations apply in strict block order: by block height, then by transaction index within the block. Replaying the same blocks under these rules MUST be deterministic.
- Mempool state is never protocol state. Every validity decision is made at confirmation, against the confirmed ledger at that point (reference).
- Cursed inscriptions (inscriptions assigned negative numbers under the Ordinals rules) are not valid BRC-20 operations.
5. State transitions
Each address holds, per ticker, an available balance and a transferable balance. Overall balance is their sum. The two-phase transfer is the heart of the protocol: it is why a BRC-20 balance can move by spending an inscription in an otherwise ordinary Bitcoin transaction.
| Event | Available | Transferable | Overall |
|---|---|---|---|
| deploy confirmed | unchanged | unchanged | unchanged (opens the ticker) |
| mint confirmed | +amt | unchanged | +amt |
| transfer inscribed | -amt | +amt | unchanged |
| first spend, to recipient | recipient +amt | -amt | sender -amt, recipient +amt |
| first spend, to self | +amt | -amt | unchanged |
| first spend, as fee | +amt | -amt | unchanged |
6. Invalid conditions
Two different failure classes exist. Content that fails R1, R2, or R4 is not a BRC-20 inscription at all. Content that passes those but breaks any other rule is an invalid BRC-20 operation: recognized, recorded by some indexers for diagnostics, but with zero ledger effect. Both classes leave balances untouched.
| Condition | Class | Rule |
|---|---|---|
| Content is not one JSON object | Not BRC-20 | R1 |
p missing or not "brc-20" | Not BRC-20 | R4 |
| Numeric field written as a JSON number | Invalid operation | R3 |
Unknown op value | Invalid operation | R5 |
Ticker not 4 bytes (or 5 with self_mint) | Invalid operation | R7 |
| Second deploy of an existing ticker | Ignored deploy | R10 |
dec above 18, or not an integer string | Invalid deploy | R9 |
lim greater than max | Invalid deploy | R9 |
| Value over the uint64 maximum | Invalid operation | R9 |
More fractional digits than dec | Invalid operation | R11 |
| Mint of an undeployed ticker | Invalid mint | R12 |
amt above lim | Invalid mint | R13 |
| Mint after supply is fully minted | Invalid mint | R14 |
Transfer amt above available balance | Void transfer inscription | R16 |
| Second spend of a transfer inscription | No effect | R18 |
| Cursed inscription | Not BRC-20 | R24 |
7. Extensions
Self-issuance and 5-byte tickers
A governance-approved extension to the original rules allows deploys carrying
"self_mint": "true" to claim tickers of exactly 5 UTF-8 bytes. For such tickers
only the deployer may mint. Classic 4-byte tickers are unaffected. This site documents the
extension because 5-byte tickers exist in the live ledger and Universe indexing accepts 4 and
5 byte tickers for marketplace evidence.
Programmable extensions
Later upstream proposals (often grouped as BRC2.0) add balance-affecting programmable
behavior on top of the classic three operations. They are out of scope for this
specification. The Bitcoin Universe read model represents classic
deploy / mint / transfer economics only and does not
index programmable extensions.
8. Universe indexing decisions
Everything below is a Bitcoin Universe implementation decision layered on the upstream rules, stated here so readers can tell the two apart.
- Atomic integer arithmetic. Universe stores every amount as a base-10
integer string scaled by the ticker's
dec(an "atomic" amount), and performs all arithmetic on integers. Display amounts are validated against the exact grammar in R11 before scaling. - Invariant enforcement. The read model transactionally rejects any
event batch that would push minted supply past
max, exceed a per-mintlim, drive any balance negative, or mutate immutable deploy economics. A violation rolls back the entire batch. - Ticker identity. Tickers are lowercased for identity and the original display casing is preserved, exactly as R8 requires.
- Marketplace evidence bounds. Transferable-inscription evidence is accepted only for tickers of exactly 4 or 5 UTF-8 bytes with divisibility 0 through 18, and only for confirmed events with the two transfer phases recorded separately.
- Coverage honesty. The Universe BRC-20 source publishes
partialcoverage: confirmed history and holder state are indexed, and there is no exhaustive mempool feed with a stable pending lifecycle. - Classic operations only. Programmable extensions are not represented in the read model (section 7).
9. References
- Original BRC-20 documentation (domo, March 2023)
- Layer1 Foundation BRC-20 indexing rules
- OPI reference indexer
- Ordinals handbook (inscription carrier)