Reference
How the readers behave.
Confirmation, mempool and reorg semantics differ sharply between the three protocols. So do their guarantees. This page states each one separately rather than averaging them into a comfortable summary.
Terminology
| Term | Meaning |
|---|---|
| Carrier | A single OP_RETURN output, including its opcode and every data push. |
| Payload | The concatenation of the data pushed by every push in the carrier. Push boundaries carry no meaning. |
| Reference | The normalised, NFC lowercase form of an OP-20 ticker. Identity is compared on the reference, never on the text as written. |
| Receipt output | The spendable output that determines who owns the result of an OP Names registration or transfer. |
| Address custody | An OP Names state where the owner is an address. The name moves only by an authorised explicit transfer. |
| UTXO custody | An OP Names state where the owner is a specific outpoint. The name follows spends of that outpoint to output 0. |
| Burned | An OP Names terminal state reached when a receipt or follow output cannot hold an owner. The registration stays valid history but has no owner. |
| Evidence | A recognised but rejected payload, stored with its reason so the decision is auditable. Evidence never becomes an asset. |
| Coercion | A recorded, named adjustment applied to a legacy value, for example truncating an all zero fraction from an amount. Coercions are reported, never silent. |
| Provisional | An OP Inscriptions record that is indexed but not yet past the configured confirmation count, and is therefore still removable by a reorg. |
| Fail closed | Refusing to act when the required proof is unavailable, rather than guessing. All three readers do this. |
Indexer semantics
Confirmation
| OP-20 | OP Names | OP Inscriptions | |
|---|---|---|---|
| Listing minimum confirmations | not applicable | not applicable | none recorded |
| Settlement minimum confirmations | not applicable | not applicable | 1 |
| Recorded policy | No supported marketplace mutation reaches a confirmed local state. | No supported marketplace mutation reaches a confirmed local state. | A fill is recorded only after the exact receipt spend, buyer receipt and seller payout are confirmed on-chain. |
For OP-20 and OP Names, protocol state itself still comes from confirmed transactions. The rows above describe marketplace lifecycle, which for those two protocols does not exist.
Mempool
- OP-20. Pending activity coverage is deliberately reported as
unavailable. The authoritative ledger and public API expose confirmed state, and no exhaustive mempool activity feed exists behind them. An application must not present an unconfirmed OP-20 movement as fact. - OP Names. The same. Pending and mempool coverage is reported as unavailable. The raw block authority replays confirmed blocks only.
- OP Inscriptions. Ownership for a marketplace mutation is re-resolved live through a mempool compatible Bitcoin API, so an in flight spend can be observed. Indexer tip lag is not compared with node tip, so freshness is not numerically enforced.
Reorg behaviour
| Automatic reconciliation | Recorded policy | |
|---|---|---|
| OP-20 | no | The read-only feed has no local lifecycle reconciliation. |
| OP Names | no | The read-only feed has no local lifecycle reconciliation. The raw block authority itself does roll back: at every poll the durable tip is compared with the node, a shallow reorganisation is rolled back one block at a time against verified before-images, and a divergence beyond the configured maximum depth fails closed and leaves readiness false. |
| OP Inscriptions | yes | The reconciler reopens receipts that are unspent on the active chain and marks conflicting spends stale. Restart reconciliation finds a common ancestor first; a bounded provisional suffix is deleted and replayed, and a deep or already final divergence persists a halt rather than rewriting authoritative rows. |
Sources of truth
| Concern | OP-20 and OP Names | OP Inscriptions |
|---|---|---|
| Order book | Read-only marketplace feed | Universe SQL OP inscription market orders |
| Ownership | No supported mutation authority | Current title receipt resolved through a mempool compatible Bitcoin API |
| Settlement | No supported settlement registration | Exact title outpoint spend and buyer receipt output observed through the Bitcoin API |
| Protocol state | Protocol API with legacy fallback | Standalone OP Inscriptions indexer for catalogue reads |
| Mutation gate | All legacy replay-key mutations are rejected | Live title receipt is re-resolved, but indexer tip lag is not compared with node tip |
| Freshness enforcement | none | none numeric; ownership is checked per mutation |
Fee and size
- OP_RETURN bytes are non witness data and are charged at four weight units per byte. There is no discount.
- Keeping the whole scriptPubKey at 83 bytes or fewer keeps the transaction relayable under both the long standing default policy and current defaults.
- The data output holds zero value, so it does not consume a dust threshold, but the receipt output does. Budget 546 satoshis for a witness v0 receipt and 330 satoshis for a taproot receipt as practical minimums.
- A rejected payload costs the same fee as an accepted one. Validate before you broadcast, not after.
- Splitting a payload across several pushes changes the script size by one prefix byte per extra push and changes nothing else. It does not reduce cost.
Funding safety: never spend an asset bearing output
This is the sharpest practical hazard on this carrier. Protocol assets ride ordinary looking spendable outputs. A pending legacy OP-20 transfer UTXO, a name custody outpoint and a listed asset are all indistinguishable from plain change to a naive coin selector. Spending one as fee input moves or destroys whatever it carries.
Bitcoin Universe Core screens funding candidates against its own OP-20 records before selecting them. The properties worth copying are these:
- First party records, batched. Candidate outputs are checked against Core's own transfer, domain and trade records in a small number of batched lookups keyed by transaction id and by outpoint, rather than one query per candidate.
- A bare transaction id key when the record has no output index. When a record names a transaction but not a specific output, every output of that transaction is treated as asset bearing. The screen refuses to guess which output was meant.
- Fail closed on unreadable records. If the screening lookup itself fails, the operation is refused with a payment safety error. It does not fall back to unscreened selection.
- Screening happens before selection, not after. A flagged outpoint is skipped while the funding total is still being accumulated, so it never reaches the signing step.
An address balance is not a spendable balance on this carrier. Any wallet that funds a transaction from a plain UTXO list, with no protocol aware exclusion set, will eventually burn a user's asset as change. Treat the exclusion set as a required input to coin selection, and treat its unavailability as a hard stop.
Security considerations
- Interpretation is not consensus. An OP-20 balance or a name ownership record is one indexer's reading. A different indexer with a different rule set will produce a different answer, and Bitcoin will not arbitrate.
- Payload addresses are not authority. The OP Inscriptions marketplace authority explicitly does not trust addresses written in a payload, replay keys, or a first spendable output heuristic. Neither should you.
- Retired mutation paths fail closed. The legacy random key and replay key marketplace mutations return HTTP 410. An interface that still shows those buttons can reach a broadcast step before the failure, which is a real way to lose fees.
- Homograph names. OP Names rejects a list of Unicode dot lookalikes precisely because a name that renders like
a.btcbut uses a different code point would otherwise be a distinct identity. Compare normalised names, never rendered text. - Duplicate JSON keys. A permissive parser keeps the last value; an attacker chooses the parser. Both readers check for repeated top level keys textually, before parsing.
- Amount coercions must be visible. When a legacy value is truncated, the coercion is named and recorded. Silent truncation would let a payload mean one thing to a writer and another to a reader.
- Deep reorgs are an operator decision. A divergence past the configured maximum depth halts rather than rewriting final rows, and the halt is not auto cleared.
- Report vulnerabilities privately. Use the private advisory link in SECURITY.md.
Limitations
- No mempool activity feed for OP-20 or OP Names. Unconfirmed state is not available and should not be simulated.
- No enforced freshness contract. None of the three readers compares indexer tip lag against node tip with a numeric threshold, so a stale read is possible and is not signalled by a lag error.
- No OP-20 or OP Names marketplace execution. Listing, buying, offers, settlement and reconciliation are all unsupported, and the retired paths return HTTP 410.
- No atomic listing update for OP Inscriptions. Cancel and relist.
- No offer workflow for any of the three protocols.
- The OP Names raw block authority is code complete but deliberately not production enabled. Its scan, browse, genesis, canary and execution gates all default off, and readiness stays false until an independently reviewed genesis determination, a full replay, corpus reconciliation and read only canaries are done.
- The OP Names replay boundary is an operational starting point chosen conservatively below the earliest observed activity. It is not proof that no older protocol event exists.
- OP-20 assets with incomplete historical activity or unresolved custody are retained as diagnostic state and excluded from usable authority rather than shown with an approximate balance.
- Some historical OP-20 balance rows contain null addresses, negative corrections, or integers beyond JavaScript's exact range. Those rows are never shown as wallets and are never rounded.
Implementation checklist
For anyone writing a reader, a wallet or an explorer against this carrier.
Carrier handling
- Reject a non push opcode inside the carrier instead of skipping it, unless you are building a catalogue rather than an authority.
- Reject a push whose declared length exceeds the script.
- Concatenate pushes in order; do not assume a single push.
- Decode strictly as UTF-8 for OP-20 and OP Names. Do not fall back to a lossy decoder.
- Bound the assembled payload. 4096 bytes is the bound the organisation's reader uses.
Protocol handling
- Check for repeated top level JSON keys textually, before parsing.
- Enforce the exact allowed field set per operation. Do not accept extension fields.
- Normalise identity before comparison: NFC, trim, lowercase, and for names apply the dot lookalike and path separator rejections.
- Count OP_RETURN outputs. OP-20 needs exactly one OP-20 carrier; OP Names needs exactly one OP_RETURN output in the whole transaction.
- Model the OP-20 legacy two stage transfer explicitly. Do not collapse it.
- Derive the OP Names receipt index from the carrier index, not from a fixed constant.
- Treat burned names as valid history with no owner, not as unregistered.
- Assemble multi part OP Inscriptions content only when every part is present exactly once.
Operational handling
- Commit block, records and cursor in one transaction.
- Verify each block against a fresh height to hash lookup and its expected parent, and use an independent verifier where you can.
- Keep new records provisional until a configured confirmation count, and advance finality monotonically.
- On restart, find a common ancestor before mutating anything.
- Halt rather than rewrite on a deep or already final divergence, and do not clear the halt automatically.
- Screen funding candidates against your own asset records before coin selection, and fail closed when that screen is unavailable.
- Report coverage honestly, including reporting pending activity as unavailable when you have no mempool feed.