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.
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
| Field | Why it exists | Minimum 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.
- Emit invalidations newest first, so a consumer applying them in order never sees an inconsistent intermediate state.
- Reverse every ledger mutation the orphaned branch made, in the reverse of the order it made them.
- Restore allocations the orphaned branch had marked spent, at their original outpoint, amount and offset.
- Remove allocations the orphaned branch created. They never existed on the chain that survived.
- 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.
| From | Event | To | Rule | Accounting |
|---|---|---|---|---|
| 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.
| Operation | Wallet deltas | Supply deltas | Addresses | Rule |
|---|---|---|---|---|
| deploy | None. A deploy has no economic effect. |
All zero. |
Deployer only. No sender, no receiver. |
DUST-9.5 |
| mint | Sum to |
total, circulating and minted all |
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 |
total and circulating |
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.