Protocol version 1 — not frozen

The ORD20 protocol

ORD20 defines fungible tokens whose amount is the satoshi value of the output that holds them. There is no separate ledger and no amount written in a text: if an output is worth 12,000 satoshis, it holds 12,000 units. Every token output is locked by a covenant that constrains how it may be spent, so a transaction that breaks the rules is rejected by the network itself.

One thing a script cannot check is where an output came from. That is the indexer's job: it follows the chain from the deploy onwards and decides whether an output really descends from a real token. An imitation built out of ordinary satoshis can carry the same script, but it has no ancestry, and no indexer will count it.

Amounts and identity

The smallest unit is one satoshi and is called an ORDS. Decimals are fixed for every ORD20 token at dec = 2, so one token is one hundred ORDS. It is a constant of the protocol, not a field an issuer can set.

A token is identified by its id: the transaction that deployed it plus the output index of its card. The symbol is a label of one to twelve characters from A–Z and 0–9, and it is deliberately not unique — two different tokens may both call themselves ORDN. Anything that tells a holder which of the two is which comes from outside the protocol: the ORDnet .web3 registry can attest that an issuer and a symbol belong together, and a wallet may show that as a badge. It is a label, never a consensus rule.

Never match on the symbol Any software that looks a token up by name instead of by id will eventually accept the wrong one. Balances, transfers and listings are all keyed on the id.

The token card

The card is the only JSON in the protocol. It sits in the first output of the deploy and fixes the parameters of the token for good. Mints and transfers carry no JSON at all — their meaning is in the script and in the output values.

{   "p": "ord-20", "op": "deploy", "ver": 1,   "sym": "EXAMPLE", "name": "Example token",   "cap_mode": "capped", "cap": "100000000",   "premint": "0", "x": "100000",   "mint_fee": "1000", "m1_enabled": true,   "fee_default": "token", "mint_vout": 1 }
cap_mode, cap Capped with a ceiling in units, or uncapped. A capped token can never issue more than its cap.
premint What the issuer takes when activating. Visible before anyone else mints a single unit.
x The most a single public mint transaction may take. Not a per-address limit — a script has no memory of addresses.
mint_fee Satoshis paid to the issuer per public mint transaction, enforced by the contract.
m1_enabled Whether public minting is open at all. An active mint state with this off is not a public mint.
fee_default Whether a wallet should pay fees out of tokens or out of BSV by default. The holder can change it per transaction.

Optional fields carry the presentation: a description of at most 160 characters, a website, an icon either inline or in its own output, references to metadata and terms, the issuer's name and .web3 domain, and social links. Parsing is strict on purpose. The card must be valid UTF-8, an object may not repeat a key, amounts must be exact integers within range — 1e3, 1000.0 and a negative value are all rejected — and the card must agree with the mint state it points at. A card that does not parse is not a token.

Deploy

A deploy publishes the card in the first output, carrying exactly one satoshi, and the mint contract in the output the card points at. The mint contract starts inactive: a deploy on its own creates no units and hands out nothing. It also claims no name. Two issuers may deploy the same symbol on the same day and both deploys are valid; they are simply two different tokens.

output 0   token card (JSON), 1 sat output 1   mint contract, not activated output 2   change

Minting

Issuance is a chain of states. Each mint spends the current mint state and creates its successor, so the sequence is strictly serial and the running total lives on the chain rather than in anyone's database. There are four steps.

M0 The issuer activates the token and takes the premint. Until this happens nothing can be minted by anyone.
M1 Public minting, if the issuer left it open. Anyone may take up to x units in one transaction, paying one satoshi per unit plus the mint fee to the issuer. No waiting period, no allowance per address.
M2 The issuer issues a batch, within the same cap as everyone else.
M3 The issuer closes issuance permanently. After M3 nothing can ever be minted again, whatever the cap said.

Because minting is serial, two people who mint at the same moment are competing for the same state. One of them wins; the other is spending a state that has already been spent, and that transaction is never valid — not "ignored by the indexer", but rejected outright. A wallet handles this by waiting for the confirmed successor and trying again. When less than x remains under the cap, the next mint can only take the remainder.

Why minting costs satoshis The satoshis you pay are the ones that end up inside your tokens. That is what makes them redeemable later. A token that could be minted for free would be backed by nothing.

Transfer

A transfer spends one or more token outputs of the same token and produces up to four new token outputs of that token. Whatever you do not send returns to you as a fresh token output; nothing is lost along the way. After the token outputs a transaction may carry one ordinary change output and one memo of at most 220 bytes — and nothing else. A second ordinary output is not a valid transfer.

The miner fee comes out of your tokens or out of your BSV, and you choose per transaction; the card's fee_default only says which way a wallet should lean. Paying from tokens means those units are destroyed, because their satoshis leave the token domain to pay the miner. That is the price of never needing BSV: it is visible, it is your choice, and it is the reason a holder with nothing but tokens is not stuck.

in   token 12,000 out  token 5,000  → recipient out  token 6,985  → back to you      15 units paid the miner (fee from tokens)

Exit to BSV

A holder can always spend token outputs into ordinary BSV outputs. The units stop existing and the satoshis that were inside them become plain money again. Nobody has to agree to it, no market has to be liquid, and the issuer cannot block it. This is also how a holder pays a BSV amount with tokens, and how an unsold listing is taken back.

This is the floor under the token. One unit releases one satoshi, minus the miner fee for the transaction. Whatever a market says the token is worth, it cannot fall below what is inside it.

Listing

Selling happens on the chain, without an exchange holding anything. The seller locks a token output at a fixed price; anyone who pays that price to the seller's address completes the sale in a single transaction, and the tokens move straight to the buyer. There is no escrow, no account, no counterparty.

Version one is deliberately narrow: a whole output at a time, no partial fills, no bids, no expiry. The seller can cancel and take the output back at any time until someone buys it. A buyer funds the purchase with BSV — the payment goes to the seller as ordinary satoshis.

Provenance

Two layers decide whether something is a token. The contract checks the form: which outputs may exist, how much may move, what the mint state must look like. It cannot check history, because a script cannot see where its own input came from.

So the indexer walks back. For every token output it establishes whether the ancestry leads to a real deploy. Anyone can take ordinary satoshis and wrap them in the same locking script; it will look identical in a block explorer. It has no ancestry, and it counts for nothing. The same check catches an output that tries to appear from a path that never produced it.

the books always close: minted = in circulation + listed          + burned as fees + released to BSV          + invalidated

That identity is checked after every single transaction in the test fixtures. If it ever failed to balance, the implementation would be wrong — and it is exactly the kind of error that a second, independent implementation is there to catch.

Indexer and API

The ORDnet indexer is written in Rust and reads blocks from its own Bitcoin SV node over JSON-RPC. No third-party stream sits between the chain and the state, so there is nothing to trust in the middle. It starts at a fixed anchor block, and every answer it gives names the height it was computed at, so a caller can tell the difference between "nothing there" and "not read that far yet".

A second implementation, written independently in JavaScript, applies the same rules to the same fixture chains and must reach byte-identical results. The two exist to disagree; so far they do not.

The public read API is not built yet There is a route contract on paper, but no service behind it, so nothing is documented here as if it worked. When the API has been released, the endpoints and their guarantees appear on this page.

Status

ORD20 is version one and is not frozen. The contracts, the reference implementation and the fixture chains exist and are tested; the public API and the wallet are being built; no token has been deployed yet. This page will say so plainly at every stage, including the stages where the honest answer is "not yet".

Checking indexer…