Normative

BLOCK-20 specification

Rules a reader applies to decide what a BLOCK-20 inscription means. Every rule below is drawn from the Bitcoin Universe writer implementation and the bitcoin-universe-block20-v1 reader profile. Rule identifiers are stable.

1. Scope and authority

This document specifies how a BLOCK-20 reader interprets Bitcoin inscriptions, and what a BLOCK-20 writer emits. It is not a Bitcoin consensus rule and not a guarantee that every third-party reader will agree.

Keywords: MUST and MUST NOT describe behavior required for conformance with this profile. Reject means the inscription has no effect on token state. Ignore means the inscription is not an error but still changes nothing.

Two implementations sit behind these rules. The writer is Bitcoin Universe Inscribe, which serializes the payload and broadcasts the inscription. The reader is the bitcoin-universe-block20-v1 profile, which computes ticker state, balances, and supply. The writer performs no token validation. All validity is decided by the reader.

2. Carrier and envelope

  • R2.1

    A BLOCK-20 message MUST be carried as the content of an Ordinals inscription. The Bitcoin Universe writer reveals it through a taproot script-path spend of a dedicated commit output. The carrier MUST NOT be an OP_RETURN output.

  • R2.2

    The inscription content type MUST match text/plain or application/json, compared case-insensitively, optionally followed by parameters after a semicolon. The writer emits text/plain;charset=utf-8. Any other content type is ignored.

  • R2.3

    Content length MUST be at least 1 byte and at most 2048 bytes. Empty content and oversized content are ignored without being parsed.

  • R2.4

    The operating address for an inscription is the address that holds it at the block being processed: the reveal owner for a deploy, mint, or transfer inscription, and the destination for a later move. It MUST be a Bitcoin address supported by the reader for the configured network. Bech32 addresses MUST be entirely lowercase or entirely uppercase, and MUST carry the bc1 prefix on mainnet or tb1 on testnet. Base58 addresses MUST start with 1 or 3 on mainnet, or m, n, or 2 on testnet.

  • R2.5

    A deploy, mint, or transfer inscription whose operating address is absent or unsupported MUST be rejected. For a transfer settlement, an absent or unsupported destination is not a rejection: it settles as a burn (see R7.9).

  • R2.6

    A reader MUST associate a BLOCK-20 reveal with the output it was inscribed into. If the inscription has already moved away from its reveal transaction before the reader observes it, the reader MUST fail closed rather than guess an owner.

3. Payload grammar

BLOCK-20 does not accept general JSON. It accepts a flat object whose keys and values are all JSON strings, parsed by a strict grammar. This is deliberate: it removes the encoding ambiguity that lets two readers disagree about the same bytes.

  • R3.1

    Content MUST decode as strict UTF-8. Any invalid sequence, including an unpaired surrogate or an overlong encoding, rejects the inscription.

  • R3.2

    The decoded text MUST be exactly one JSON object. Whitespace is permitted before the opening brace, around keys, colons, commas, and after the closing brace. Any non-whitespace content after the closing brace rejects the inscription.

  • R3.3

    Every key and every value MUST be a JSON string. A number, boolean, null, array, or nested object anywhere in the payload rejects the inscription. {"amt":5} is invalid; {"amt":"5"} is the valid form.

  • R3.4

    A repeated key rejects the inscription. The reader MUST NOT apply last-wins or first-wins recovery.

  • R3.5

    A raw control character below U+0020 inside a string rejects the inscription. Escaped forms such as \n are parsed as JSON escapes and are permitted by the grammar, though no BLOCK-20 field accepts a control character in its value.

  • R3.6

    An unterminated string, a missing colon between key and value, or a missing comma between members rejects the inscription.

  • R3.7

    A payload without a p field, or whose p is not exactly the lowercase string block-20, is not a BLOCK-20 message and MUST be ignored. The comparison is case sensitive and exact.

  • R3.8

    Each operation defines an exact field set. A payload missing a required field, or carrying any field outside the allowed set for its operation, MUST be rejected. There are no reserved extension fields.

  • R3.9

    op MUST be exactly deploy, mint, or transfer. Any other value is ignored.

Field sets by operationexact, no extensions
deploy    required: p, op, tick, max, lim      optional: des
mint      required: p, op, tick, amt, hash     optional: none
transfer  required: p, op, tick, amt           optional: none

4. Identity and numbers

  • R4.1

    tick MUST match ^[A-Za-z0-9]{1,5}$: one to five ASCII letters or digits. No spaces, punctuation, emoji, or non-ASCII characters.

  • R4.2

    Ticker identity is the lowercase form of tick. BLK, Blk, and blk are the same token. The display form recorded for a ticker is the exact casing of its deploy.

  • R4.3

    The first valid deploy of an identity wins. Every later deploy of the same identity MUST be ignored, whatever supply or limit it declares.

  • R4.4

    Every numeric field (max, lim, amt) MUST match ^[1-9]\d*$. Leading zeros, a leading + or -, a decimal point, an exponent, whitespace, thousands separators, and the value 0 are all invalid.

  • R4.5

    Numeric values MUST NOT exceed 2128 minus 1, that is 340282366920938463463374607431768211455.

  • R4.6

    BLOCK-20 has zero decimal places. Every amount is a whole unit. There is no smaller subdivision and no display scaling.

5. Deploy

Deploy payloaddefines a ticker
{"p":"block-20","op":"deploy","tick":"BLK","max":"21000000","lim":"1000"}
  • R5.1

    Field set is exactly p, op, tick, max, lim, with des permitted as the only optional field.

  • R5.2

    max is the maximum supply and lim is the maximum amount creditable by a single mint. Both MUST satisfy R4.4 and R4.5.

  • R5.3

    lim MUST NOT exceed max. A deploy declaring a per-mint limit larger than the whole supply is rejected.

  • R5.4

    des, when present, MUST be at most 256 bytes of UTF-8 and MUST NOT contain a control character. It is descriptive metadata with no effect on token state.

  • R5.5

    A deploy has no economic effect. Total, circulating, minted, and burned supply all start at zero. The deploying address receives nothing.

  • R5.6

    The deploy height is the height of the block that reveals the deploy inscription. It becomes the lower bound for every mint anchor of that ticker (R6.6).

  • R5.7

    Deployment metadata is immutable. A reader MUST NOT allow a later inscription to change a ticker's display form, decimals, maximum supply, or deployer.

6. Mint and the anchor

Mint payloadcredits supply, anchored to a block
{"p":"block-20","op":"mint","tick":"BLK","amt":"1000","hash":"<64 lowercase hex>"}

The anchor is the part of BLOCK-20 that is not shared with other inscription token protocols. A mint does not merely claim an amount, it names a block, and the reader tests that claim against the chain.

6.1 The anchor derivation

Let H be the value of hash, R the height of the block revealing the mint inscription, D the ticker's deploy height, and W the reader's freshness window in blocks.

Derivationevaluated in order
step 1   H matches ^[0-9a-f]{64}$                     else reject
step 2   A := height of the block whose ID is H,
         resolved against the active chain            else reject
step 3   A >= D                                        else reject
step 4   A <  R                                        else reject
step 5   R - A <= W                                    else reject
step 6   remaining := max - minted
         if remaining <= 0                             then ignore
step 7   credited := min(amt, remaining)
  • R6.1

    Field set is exactly p, op, tick, amt, hash. No optional fields.

  • R6.2

    The ticker MUST have an active deployment at the mint's block. A mint for an unknown or deactivated ticker is ignored.

  • R6.3

    amt MUST satisfy R4.4 and MUST NOT exceed the deployment's lim. A mint above the per-mint limit is rejected outright and is not reduced to the limit.

  • R6.4

    hash MUST match ^[0-9a-f]{64}$. Uppercase hex, a 0x prefix, surrounding whitespace, a truncated hash, a transaction ID that is not a block ID, an inscription ID, a numeric height, a Merkle root, and a payload digest are all rejected by this rule or by R6.5.

  • R6.5

    The reader MUST resolve hash to a height on the active chain. Resolution succeeds only when a Bitcoin node knows the header, the header has at least one confirmation, and the block currently at that height hashes to the same value. A header from an orphaned branch fails this test, so its hash cannot anchor a mint.

  • R6.6

    The anchor height MUST be greater than or equal to the ticker's deploy height. A mint cannot point at a block from before the ticker existed.

  • R6.7

    The anchor height MUST be strictly less than the reveal height. A mint cannot anchor to its own block or to any later block.

  • R6.8

    The distance R - A MUST NOT exceed the freshness window. The reference reader uses 144 blocks by default, roughly one day of Bitcoin. The window is an operator setting in the range 1 to 10000, so a mint near the boundary can be accepted by one reader and rejected by another.

  • R6.9

    If remaining supply (max minus already-minted) is zero or less, the mint is ignored and produces no event. Supply is not exceeded and no partial credit is given after exhaustion.

  • R6.10

    When remaining supply is positive but smaller than amt, the mint is credited for exactly the remaining amount. This partial final mint is valid, and the reader records both the requested and credited amounts.

  • R6.11

    A credited mint increases the reveal owner's balance, total supply, circulating supply, and minted supply by the credited amount. Burned supply is unchanged.

  • R6.12

    Failing any of R6.3 through R6.8 credits nothing. There is no partial credit for an invalid anchor.

Where the writer gets the hash. Bitcoin Universe Inscribe reads the current chain tip from its configured block source while creating the order, and writes that block ID into both the order record and the payload. It selects the value before funding, reveal, or confirmation, and it does not refresh the value before reveal. Because the tip is always mined before the later reveal block, a normal order satisfies R6.7 naturally. It can still fail R6.8 if the order sits unfunded for more than the freshness window.

7. Transfer

Transfer payloadreserves, then settles on the first move
{"p":"block-20","op":"transfer","tick":"BLK","amt":"250"}

A transfer is two chain events, not one. Inscribing reserves an amount. Moving the inscription decides where that amount lands.

Transfer inscription state machine A transfer inscription starts in the reserved state when it is revealed, which reduces available balance without changing the holder total. Its first later move settles it in one of three ways: sent to a supported address, which moves the balance; spent in fees, which releases the reservation back to the owner; or burnt or sent to an unsupported destination, which destroys the reserved amount and reduces supply. Any move after settlement has no effect. Reserved available balance reduced Settled: transferred balance moves, supply unchanged Settled: fee return reservation released to owner Settled: burn supply reduced permanently Later moves no token effect
The first move after a transfer inscription is revealed decides the outcome. Everything after that is inert.
  • R7.1

    Field set is exactly p, op, tick, amt.

  • R7.2

    The ticker MUST have an active deployment. A transfer inscription for an unknown ticker is ignored.

  • R7.3

    Available balance is the owner's balance minus the sum of that owner's unsettled reservations for the same ticker. If available balance is less than amt, the transfer inscription is ignored and no reservation is created.

  • R7.4

    An inscription that already holds a reservation MUST NOT create a second one.

  • R7.5

    Revealing a valid transfer inscription creates a reservation. Holder balance and every supply figure are unchanged. Only available balance falls.

  • R7.6

    The first later move of that inscription settles the reservation. Settlement is evaluated once and only once.

  • R7.7

    If the move sends the inscription to a supported address, the reserved amount moves from the owner to that address. Supply figures are unchanged. When the destination equals the owner, the reservation is released and the balance is unchanged, with the movement still recorded.

  • R7.8

    If the inscription is spent in transaction fees, the reservation is released back to the owner. No balance and no supply figure changes.

  • R7.9

    If the inscription is burnt, or moves to a destination the reader cannot interpret as a supported address, the reserved amount is destroyed. The owner's balance falls, total and circulating supply fall, and burned supply rises by the same amount. Minted supply is unchanged, so a burn does not free capacity for new mints.

  • R7.10

    Any move of the inscription after settlement has no token effect.

8. Ordering and state transitions

  • R8.1

    Blocks MUST be processed in ascending height with no gaps. A reader that cannot obtain a contiguous range MUST stop rather than skip.

  • R8.2

    Within a block, items are ordered by transaction index ascending. Where a move and a new inscription share a transaction index, the move is processed first. Ties are broken by ordinal (block transfer index for a move, inscription number for a reveal), then by inscription ID.

  • R8.3

    State is applied in that order within the block. Two mints in the same block compete for the same remaining supply, and the earlier one wins.

  • R8.4

    A deploy and a mint of the same ticker in the same block are valid when the deploy is ordered first. In that case the anchor lower bound (R6.6) is that same block height, so the anchor must be an earlier block, which R6.7 already requires.

  • R8.5

    Each accepted operation MUST produce a stable event identity that does not change when the same block is replayed. The reference reader derives it from the operation and the inscription ID, plus the moving transaction ID for a settlement.

  • R8.6

    Minted supply never decreases through a burn. The supply invariant is: total equals minted minus burned, and circulating equals total.

9. Invalidity conditions

Every condition below results in no change to token state. The distinction between "ignored" and "rejected" matters only for reader diagnostics.

Conditions under which a BLOCK-20 inscription changes nothing.
ConditionApplies toRule
Content type is not text/plain or application/jsonAllR2.2
Content is empty or larger than 2048 bytesAllR2.3
Operating address absent or unsupported for the networkDeploy, mint, transfer revealR2.5
Content is not strict UTF-8AllR3.1
Trailing content after the JSON objectAllR3.2
Any non-string key or valueAllR3.3
Duplicate fieldAllR3.4
Raw control character in a stringAllR3.5
Missing required field or any unknown fieldAllR3.8
Ticker outside one to five ASCII alphanumericsAllR4.1
Amount with leading zero, sign, decimal point, or value zeroAll numeric fieldsR4.4
Amount above 2128 minus 1All numeric fieldsR4.5
Ticker identity already deployedDeployR4.3
Per-mint limit exceeds maximum supplyDeployR5.3
Description longer than 256 bytes or containing a control characterDeployR5.4
Ticker has no active deploymentMint, transferR6.2, R7.2
Mint amount above the per-mint limitMintR6.3
Hash not 64 lowercase hex charactersMintR6.4
Hash does not resolve to a block on the active chainMintR6.5
Anchor height below the deploy heightMintR6.6
Anchor height at or above the reveal heightMintR6.7
Anchor older than the freshness windowMintR6.8
Supply already exhaustedMintR6.9
Available balance below the transfer amountTransferR7.3
Inscription already holds a reservationTransferR7.4
Move of an inscription that is already settledTransfer settlementR7.10

10. Reorganization and finality

  • R10.1

    When a block the reader has applied is no longer on the active chain, the reader MUST invalidate every event from the replaced branch before applying the replacement branch.

  • R10.2

    Invalidation MUST proceed newest first: descending block height, then descending transaction index, then descending event index.

  • R10.3

    Invalidation MUST reverse the exact recorded wallet and supply deltas of each event, restore transfer reservations that were settled on the replaced branch, and remove reservations that were created on it.

  • R10.4

    Invalidating a deploy deactivates the ticker. A reader MUST NOT leave an applied mint or transfer depending on an inactive deployment, and MUST fail closed if that state is reached.

  • R10.5

    Events at or below the finalized height MUST NOT be invalidated. A reorganization that would require this is a fatal condition: the reader stops rather than producing a state it cannot justify.

  • R10.6

    The finalized height is the tip height minus the reader's finality depth, defaulting to 6 confirmations, and it MUST NOT move backward.

  • R10.7

    Because R6.5 resolves anchors against the active chain at the time of processing, a mint whose anchor block is orphaned by a reorganization does not survive the replay. The same inscription bytes can be valid on one chain history and invalid on another.

11. Conformance

An implementation conforms to bitcoin-universe-block20-v1 when it satisfies every MUST above and reproduces the outcomes in the test vectors. At a minimum, cover:

  • the flat string object grammar, including duplicate keys, non-string values, trailing content, and control characters;
  • exact field sets for each operation and rejection of unknown fields;
  • ticker case folding and first-deploy-wins;
  • every branch of the anchor derivation, including the exact boundaries at A = D, A = R - 1, A = R, and R - A = W;
  • partial final mints and the ignoring of mints after exhaustion;
  • reservation, transfer settlement, fee return, burn, and inert later moves;
  • within-block ordering with two competing mints;
  • reorganization invalidation ordering and the finalized-height refusal.

A reader that relaxes any rule here MUST NOT describe itself as implementing this profile, because a relaxed rule changes balances.