DUST-20 REV 1.1.0

DUST-20 documentation

Indexer semantics

Confirmation, mempool, reorganizations and what a reader must publish.

Protocol
DUST-20Registry id dust20, alias dust-20
Chain
BitcoinNetwork: mainnet
Ownership model
UTXOUnits are carried by satoshis in unspent outputs
Carrier
Inscription + spendDeploy and mint are inscribed; movement is a spend
Decimals
0Balances are whole units only
Document version
1.1.0Revised 2026-09-01
Lifecycle
ExperimentalNot a ratified multi-party standard
Owning repository
bitcoinuniverseio/dust-20Documentation source of truth

I.1 The pipeline

A DUST-20 reader needs two authoritative inputs and six stages. The inputs are an inscription index, for inscription identity, content and location, and a Bitcoin node, for complete blocks with input values, output values and output addresses. Neither is sufficient alone.

DUST-20 reader pipeline Two authoritative sources, an inscription index and a Bitcoin node, feed six sequential stages: observe, normalize, resolve, materialize, propagate and reconcile. Reconcile feeds back into observe when a reorganization occurs. Inscription index Bitcoin node identity, content, location, tip values, addresses, block continuity OBSERVE NORMALIZE RESOLVE MATERIALIZE PROPAGATE RECONCILE REORGANIZATION: INVALIDATE NEWEST FIRST, REVERSE, RESTORE, REPLAY A reader fails closed on a source gap, a mismatch between the two sources, a malformed response, an unsupported address, a finalized reorganization, or an unavailable upstream. It does not guess and it does not degrade to a partial answer.
Fig I.1 The reader pipeline. Reconcile is not a cleanup step; it is the stage that makes every earlier stage reversible.
  1. 01 / OBSERVE

    Ingest raw chain events

    Read complete blocks with input values, output values and output addresses, plus authoritative inscription identity. Record the transaction, output, inscription association and block position before declaring anything about balances.

  2. 02 / NORMALIZE

    Parse strictly and keep failures visible

    Apply the flat-string-object reader, exact key sets and strict integer parsing. Keep parse failures as recorded invalid events rather than dropping them into an unexplained empty result.

  3. 03 / RESOLVE

    Resolve deployment and history

    Fold the ticker to its identity, apply first-deploy-wins, and check the mint against the resolved unit size, the per-mint cap and remaining supply. Do not guess when two candidates conflict.

  4. 04 / MATERIALIZE

    Create allocation records with position

    An allocation is an outpoint, a ticker identity, an amount, a unit size and a satoshi offset inside that output. The offset is not optional bookkeeping, it is what makes the next spend computable.

  5. 05 / PROPAGATE

    Follow satoshis through each spend

    Concatenate input values into one range and output values into another, intersect each allocation span with each output, keep only whole units, and record the difference as burned. Emit transfer effects only where the owning address actually changes.

  6. 06 / RECONCILE

    Roll forward and roll back

    Track block association so a reorganization can invalidate newest first, reverse mutations, restore spent allocations, remove orphaned ones and replay the replacement branch. Preserve enough history to explain every transition.

I.2 The allocation record

The single most common implementation mistake is storing an amount per outpoint and nothing else. Without the satoshi offset, the next spend cannot be computed, and the reader silently diverges from every reader that stored it.

The minimum an allocation record must hold
FieldWhy it existsMinimum implementation
outpoint

Identifies the actual Bitcoin output holding the units.

Store txid, vout, output value, address where available, and spent status.

offset_sats

Locates the colored range inside the output. Without it the next spend cannot be computed.

Store the satoshi offset at which this allocation begins within its output.

tick + unit_sats

Binds the output to a resolved deployment rule.

Preserve the original spelling for display and the folded identity for comparison.

amount

Lets a client recheck the unit arithmetic independently.

Store exact integers as strings; assert amount × unit_sats fits within the output.

status

Distinguishes pending, confirmed, spent, invalidated and unknown.

Never present unknown or stale state as a confirmed balance.

source + observation

Explains who made the interpretation and when.

Expose upstream identity, retrieval time, observed height and coverage label.

origin inscription

Traces an allocation back to the mint that created it.

Retain the originating inscription id through every split and merge.

I.3 Confirmation and pending

DUST-20 defines no finality threshold. What it does define is that confirmed and pending are distinct states which must never be blurred together.

Confirmed

Carries block height, block hash, transaction index and event index. All four, or the event is not confirmed. Partial placement is rejected rather than filled in.

Pending

Carries none of those, and a confirmation count of zero. An event that has a height and calls itself pending is a bug in the reader, not an edge case.

Depth

The protocol sets no threshold. Publish your own finality depth, show confirmation counts to users, and never present unconfirmed state as settled.

Coverage

Every answer carries a coverage label of complete, partial or unavailable, plus a checkpoint of network, height, hash, finalized height and observation time. A consumer that ignores coverage cannot tell a quiet ticker from a stalled reader.

Mempool coverage is partial

The Bitcoin Universe production reader declares coverage partial precisely because it has no exhaustive mempool feed with a stable pending lifecycle and disappearance handling. Confirmed history and complete holder snapshots are indexed; unconfirmed movement is not a reliable input to an irreversible decision. This is a published limitation, not a temporary gap.

I.4 Reorganizations

A DUST-20 balance is only as final as the depth it was confirmed at. When the chain moves, a reader does not patch its state; it unwinds and replays.

  1. Emit invalidations newest first, so a consumer applying them in order never sees an inconsistent intermediate state.
  2. Reverse every ledger mutation the orphaned branch made, in the reverse of the order it made them.
  3. Restore allocations the orphaned branch had marked spent, at their original outpoint, amount and offset.
  4. Remove allocations the orphaned branch created. They never existed on the chain that survived.
  5. Replay the replacement branch from the fork point, as if it had always been the chain.

Replace-by-fee deserves separate attention. A replacement transaction can have a different output layout, which moves the boundaries in the output range, which changes which whole units survive. A replacement can burn units the original would have preserved. Derive state from the transaction that actually confirmed, never from the one you broadcast, and never rebroadcast blindly.

Every state transition DUST-20 defines
FromEventToRuleAccounting
No ticker

Valid deploy inscription

Ticker deployed, 0 minted DUST-5.1 to DUST-5.7 The identity is claimed permanently. A second deploy of the same identity changes nothing.
Ticker deployed

Valid mint inscription in an output of exactly sats satoshis

Allocation live at that outpoint, offset 0 DUST-6.1 to DUST-6.9 Minted supply increases by amt. Total and circulating supply increase by amt.
Allocation live

The carrying output is spent, whole units land in supported outputs

Allocation spent, new allocations live DUST-7.3, DUST-7.4 Wallet deltas sum to zero across the event. Supply is unchanged.
Allocation live

The carrying output is spent, some units land nowhere whole

Allocation spent, remainder burned DUST-8.1 to DUST-8.4 Total and circulating supply fall by the burned amount. Minted supply is unchanged.
Allocation live at confirmed depth

The confirming block is orphaned by a reorganization

Allocation invalidated, prior state restored, replacement branch replayed DUST-9.6 Invalidations are emitted newest first. A balance is only as final as the depth it was confirmed at.
Pending event

The transaction is replaced or evicted from the mempool

No event DUST-9.3, DUST-9.8 Coverage is partial, so a pending event may disappear without a stable notification.

I.5 Event contract

What a reader publishes, so that a downstream consumer can check the arithmetic instead of trusting it. These constraints are enforced on every accepted batch by the Bitcoin Universe production reader.

Per-operation accounting constraints
OperationWallet deltasSupply deltasAddressesRule
deploy

None. A deploy has no economic effect.

All zero.

Deployer only. No sender, no receiver.

DUST-9.5
mint

Sum to +amt.

total, circulating and minted all +amt. burned zero.

Receiver only. A mint has no sender.

DUST-9.4
transfer

Sum to zero.

All zero. Movement creates and destroys nothing.

Sender and receiver both present.

DUST-9.4
burn

Sum to -amt.

total and circulating -amt, burned +amt, minted zero.

Sender only. A burn has no receiver.

DUST-8.4

Two further constraints apply to every event. Each wallet delta must equal its own received minus sent, so a consumer can verify the arithmetic per address rather than only in aggregate. And an address may appear at most once per event: repeating it would let two rows disagree about the same balance change.

There is no agreed DUST-20 API

The production reader exposes its own routes with authentication, stable cursors and explicit coverage labels, but that is one service's contract, not a standard. Validate remote responses against a schema you control, and treat coverage, source identity and observation height as part of every answer rather than as metadata you can drop.

Checklist

The complete implementation checklist, including the reader, identity, allocation, publication and application requirements, is on the reference page.