DUST-20 REV 1.1.0

Normative

Reference

Field ledger, formulas, fee and size, limitations, checklist.

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

R.1 Operations

Four operations exist. Two are written messages carried by inscriptions. Two are outcomes of transaction shape that nobody writes down.

The four operations, and what physically carries each one
OperationCarrierRequired fieldsOptionalProvenance
DeployCreates a ticker and fixes the satoshi backing rule for every one of its units. Inscription p op tick supply unit_sats max_sats lim_sats VERIFIED
MintCreates units in a Bitcoin output whose value equals the declared satoshi backing. Inscription p op tick amt sats none VERIFIED
TransferAn ordinary Bitcoin spend. There is no transfer inscription. Bitcoin spend none none UNIVERSE
BurnA derived outcome, not an operation anyone writes. Bitcoin spend none none UNIVERSE
Deploy

A deploy declares the maximum supply, the exact satoshis that back one unit, the total backing that follows from those two numbers, and an optional per-mint satoshi cap.

Mint

A mint resolves an accepted deployment, states an amount of whole units, and states the satoshis backing them. The Bitcoin output that carries the inscription must hold exactly that many satoshis.

Transfer

Units follow the satoshis that carry them, in ordinal first-in-first-out order. A whole unit that lands entirely inside one supported output survives; anything else is burned. No JSON payload participates.

Burn

Units are burned when the satoshis carrying them are paid to miners as fees, sent to an output the indexer cannot attribute to an address, or split so that no whole unit fits inside a single output.

R.2 Field ledger

Every field of every operation. Byte counts are the range of the value literal in UTF-8, excluding the quotes. Each constraint is exactly what the decoder enforces.

Every field of every operation, with its exact constraint
FieldOpsTypeReqBytesConstraint and ruleProvenance
p deploy mint string yes 7

Exactly "dust-20".

Content whose "p" is not the literal dust-20 is not a DUST-20 message and is ignored. The protocol identifier is matched literally. There is no aliasing, casing tolerance, or versioned variant.
VERIFIED
op deploy mint string yes 4 or 6

Exactly "deploy" or "mint".

Any other operation value is rejected. No transfer or burn inscription exists. The production indexer rejects an inscription whose op is anything other than deploy or mint, including op: "transfer".
VERIFIED
tick deploy mint string yes 1 to 64

Unicode NFC text, 1 to 64 UTF-8 bytes, with no control characters, whitespace, or the URL delimiters / ? # \.

The identity of a ticker is its NFC form case-folded to lower case. A mint resolves against that folded identity. The legacy guide says the ticker is not limited to four bytes but does not settle case handling or duplicates. The production indexer settles both: identity is NFC plus lower-case folding, and the first valid deployment of an identity wins. Later deploys of the same identity are rejected.
UNIVERSE
supply deploy uint128 string yes 1 to 39

Strict positive decimal string matching /^[1-9][0-9]*$/, at most 2^128 - 1.

Total whole units that may ever be minted for this ticker. No leading zeros, no sign, no decimal point, no exponent, no whitespace. DUST-20 balances have zero decimal places, so a unit is always a whole number.
VERIFIED
unit_sats deploy sats string yes 1 to 16

Strict positive decimal string, at most Bitcoin’s monetary supply of 2,100,000,000,000,000 satoshis.

The exact number of satoshis that back one unit for the entire life of the ticker. 546 is a common documented example because it is Bitcoin’s usual dust threshold for P2WPKH. It is not a default. A payload that omits unit_sats is rejected, so never assume 546.
VERIFIED
max_sats deploy sats string yes 1 to 16

Strict positive decimal string that equals supply × unit_sats and does not exceed 2,100,000,000,000,000.

Rejected unless it equals supply × unit_sats exactly, computed with exact integer arithmetic. This is a redundancy check, not an independent quantity. It exists so a reader can detect a builder that computed the backing with floating point or the wrong unit size.
VERIFIED
lim_sats deploy sats string no 1 to 16

Optional strict non-negative decimal string, at most max_sats. Omitted or "0" means no per-mint limit.

When present and greater than zero, every mint of this ticker must satisfy sats ≤ lim_sats. The cap is expressed in satoshis, not units. The equivalent unit cap is lim_sats ÷ unit_sats. A lim_sats that is not a whole multiple of unit_sats simply makes the effective unit cap the floor of that division.
VERIFIED
amt mint uint128 string yes 1 to 39

Strict positive decimal string matching /^[1-9][0-9]*$/, at most 2^128 - 1.

Whole units to create. Rejected if previously minted units plus amt would exceed supply. Zero, negative, fractional, and leading-zero values are rejected outright.
VERIFIED
sats mint sats string yes 1 to 16

Strict positive decimal string that equals amt × unit_sats of the resolved deployment.

Rejected unless it equals amt × unit_sats, and unless the Bitcoin output carrying the inscription holds exactly this many satoshis. Three numbers must agree: the deployment ratio, the sats field in the JSON, and the real output value on Bitcoin. A one-satoshi difference invalidates the mint.
VERIFIED
Numeric ceilings a reader enforces
QuantityCeilingRule
Satoshi fields2,100,000,000,000,000DUST-3.3
Unit quantities340282366920938463463374607431768211455DUST-3.4
Content size4096 bytesDUST-2.3
Ticker length1 to 64 bytesDUST-4.3
Decimal places0DUST-5.8

R.3 Formulas

The only arithmetic in DUST-20. All of it must be evaluated with exact integers: a 64-bit float loses precision above 253, which is well inside the satoshi range.

Every arithmetic relationship in the protocol
ExpressionApplies toMeaningRuleProvenance
max_sats = supply × unit_sats deploy

Total backing is supply multiplied by the satoshis behind one unit.

1,000,000 units × 546 sats = 546,000,000 sats
DUST-5.4 VERIFIED
sats = amt × unit_sats mint

The satoshis a mint declares are the units it creates multiplied by the unit size.

100 units × 546 sats = 54,600 sats
DUST-6.4 VERIFIED
output_value = sats mint

The Bitcoin output that carries the mint inscription must hold exactly the declared satoshis.

A mint declaring 54,600 sats must sit in an output worth exactly 54,600 sats.
DUST-6.7 VERIFIED
mint_unit_cap = floor(lim_sats ÷ unit_sats) deploy

A satoshi cap per mint implies a whole-unit cap per mint.

54,600 ÷ 546 = 100 units per mint
DUST-5.6 UNIVERSE
input_units = surviving_units + burned_units transfer

Units leaving an input either land whole inside a supported output or are burned. Nothing else can happen to them.

91 units in produces 10 to the receiver, 81 as change, 0 burned
DUST-7.4 UNIVERSE
output_backing = units_in_output × unit_sats transfer

Every output carrying units must hold at least the satoshis those whole units occupy, positioned so each unit fits entirely inside it.

81 units × 546 = 44,226 sats of backing
DUST-7.4 UNIVERSE
fee = sum(inputs) - sum(outputs) transfer

The miner fee is whatever the transaction does not pay out. Any colored satoshi that falls into that gap is burned, so fees must be funded by ordinary bitcoin.

Fund the fee from a separate cardinal input, never by shrinking a colored output.
DUST-7.8 UNIVERSE

R.4 Fee and size considerations

Payload bytes are almost never the expensive part of a DUST-20 transaction. Locked backing and output count are.

Payload size is small and nearly constant

A deploy payload is typically 110 to 130 bytes of JSON and a mint is 60 to 70 bytes. Both sit in the witness, so they are discounted to one weight unit per byte. Payload size is almost never what makes a DUST-20 transaction expensive.

Backing is locked capital, not a fee

A mint of 100 units at 546 satoshis per unit puts 54,600 satoshis into an output and keeps them there for as long as you hold the units. Sizing a deployment is a decision about how much bitcoin every holder must immobilise.

unit_sats below the relay dust threshold is valid but unspendable

DUST-20 permits any positive unit_sats, and a reader will accept it. Bitcoin nodes will not relay an output below the standard dust threshold for its script type, which is 546 satoshis for P2WPKH and 330 for P2TR. Check the threshold for the output type you will actually use.

Colored change adds an output, and outputs cost more than payload bytes

A safe partial send needs a receiver output, a colored change output, a cardinal change output and at least one cardinal input. Budget for that shape rather than for the smallest transaction that would confirm.

Never let the fee come out of backing

A wallet that subtracts the fee from the largest output will silently shrink a colored output, move the colored span, and burn units. Fee funding must come from cardinal inputs, and the builder must verify every colored output value after the fee is applied.

Consolidate deliberately, not automatically

Merging allocations of one identity into a single output is valid and reduces future fees. Automatic consolidation that treats colored outputs as ordinary change will destroy units, so consolidation must be an explicit DUST-20 aware operation.

Worked cost shape for a safe partial send

Sending 10 of 91 units of a ticker deployed at 546 satoshis per unit needs: one colored input (49,686 sats), one cardinal input to fund the fee, a receiver output of 5,460 sats, a colored change output of 44,226 sats, and a cardinal change output. Five entries, not two. Budget for that shape rather than for the smallest transaction that would confirm.

R.5 Limitations

What DUST-20 cannot do, and what it costs to use. None of these are bugs; they follow from binding units to satoshis.

Validity is an interpretation, not consensus

Bitcoin does not know DUST-20 exists. Every balance is one reader’s conclusion from applying these rules to the chain. Two readers that differ on a rule will differ on a balance, and Bitcoin will not settle the argument.

Most transfer behaviour is settled by one implementation

The legacy specification documents deploy and mint and one colored-UTXO transfer example. Ordinal flow, burn conditions, ticker identity and output ordering are settled here by the Bitcoin Universe production indexer. Rules labelled UNIVERSE are a working profile, not a multi-party agreement.

Holding units immobilises bitcoin

Backing is real bitcoin sitting in an output. A large supply at a large unit_sats can require more bitcoin than the deployer expects, and DUST-5.5 rejects a deployment that would require more than exists.

Units are indivisible and non-fractional

There are no decimals. A holder cannot send half a unit, and a unit that cannot be placed whole in an output is destroyed rather than rounded.

There is no reliable unconfirmed view

The production indexer declares partial coverage: no exhaustive mempool feed, no stable pending lifecycle, no disappearance handling. Applications must not present unconfirmed DUST-20 state as settled.

Trading DUST-20 inside Bitcoin Universe is not available

Marketplace availability for DUST-20 is read-only. Listing, buying, offers and settlement are all unavailable until a typed authoritative ownership resolver exists. See the Universe support page for the exact recorded reason.

Replacement can change the outcome

Replace-by-fee can alter the output layout, which changes where colored satoshis land. A replacement can burn units the original would have preserved, so state must be derived from the transaction that actually confirmed.

R.6 Implementation checklist

Everything a conforming implementation has to do, grouped by the part of the system that does it. Each line names the rule it satisfies.

Reader

Reader checklist
RequirementRule

Decode content as UTF-8 and reject anything over 4096 bytes.

DUST-2.2, DUST-2.3

Reject nested values, non-string values, duplicate keys and trailing content.

DUST-2.4 to DUST-2.6

Parse every quantity as a strict decimal string into an exact integer type.

DUST-3.1, DUST-3.5

Enforce the exact key set per operation; never ignore an unknown field.

DUST-5.1, DUST-6.1

Record rejected payloads as invalid events rather than discarding them.

DUST-9.7

Identity and state

Identity and state checklist
RequirementRule

Fold tickers with NFC plus lower case, and keep the written spelling for display.

DUST-4.5, DUST-4.6

Apply first-deploy-wins by height, then transaction index, then inscription order.

DUST-5.7

Check every mint against the resolved deployment, not against its own payload.

DUST-6.2

Compare the declared sats against the real output value before accepting a mint.

DUST-6.7

Reject a mint into an output that already carries an allocation.

DUST-6.9

Allocation

Allocation checklist
RequirementRule

Store a satoshi offset with every allocation.

DUST-7.2

Compute movement by concatenating input and output ranges in index order.

DUST-7.3

Keep only whole units, and record the difference as burned.

DUST-7.4, DUST-8.3

Treat output order as significant and never normalize it away.

DUST-7.5

Account for fee burns and unattributable-output burns in supply.

DUST-8.1, DUST-8.2, DUST-8.4

Publication

Publication checklist
RequirementRule

Give every event a stable source event id.

DUST-9.1

Require complete block placement on confirmed events and none on pending events.

DUST-9.2, DUST-9.3

Balance wallet deltas per operation, and reject an address appearing twice.

DUST-9.4

Emit deploys with no economic effect.

DUST-9.5

Publish a coverage label and a checkpoint with every answer.

DUST-9.7

Invalidate newest first on a reorganization and replay the replacement branch.

DUST-9.6

Wallet and application

Wallet and application checklist
RequirementRule

Show the receiver, colored change, cardinal funding and fee as distinct roles before signing.

DUST-7.7

Block a partial send that has no colored change output.

DUST-7.7

Fund fees from cardinal inputs and re-verify colored output values after fee application.

DUST-7.8

Revalidate outpoints at build time, not at page load.

DUST-9.7

Treat disagreement between two readers as a blocking error, not a choice.

DUST-9.7

R.7 Where sources disagree

The legacy specification and the current implementation do not agree about everything, and earlier versions of this document left several questions open. Both positions are published here rather than silently resolved.

Is max_sats required in a deploy?

VERIFIED
Legacy position

The legacy profile includes max_sats and frames it as supply × unit_sats. Earlier versions of this documentation additionally reported that a builder emitted deploys without max_sats, and labelled the question an unreconciled compatibility split.

Current implementation

The production indexer requires max_sats. Its deploy key set is exactly p, op, tick, supply, unit_sats, max_sats, with lim_sats optional, and a deploy missing max_sats is rejected rather than inferred.

Resolution

Resolved in favour of required. Emit max_sats and verify it equals supply × unit_sats. A deploy without it is not indexed by the current implementation.

Is there an official transfer payload?

UNIVERSE
Legacy position

The legacy guide documents deploy and mint JSON and a colored-UTXO transfer example, but publishes no transfer schema. Earlier documentation listed a transfer inscription as an open question and noted an application emitting a transfer preview containing amt.

Current implementation

The production indexer accepts no transfer inscription at all. Movement is derived purely from ordinal satoshi flow through ordinary Bitcoin spends.

Resolution

Resolved: there is no transfer payload. Treat any op: "transfer" inscription as invalid, and treat an application preview containing amt as a user-interface artifact, not a protocol message.

How are duplicate and differently-cased tickers handled?

UNIVERSE
Legacy position

The legacy guide states the ticker is not limited to four bytes but does not settle case normalization or which deployment wins when a name is reused.

Current implementation

Identity is the NFC form case-folded to lower case, bounded to 64 UTF-8 bytes, excluding control characters, whitespace and the delimiters / ? # \. The first valid deployment of an identity wins; later ones are rejected.

Resolution

Resolved by the current implementation. Independent implementations that compare tickers byte-for-byte will disagree with it, so preserve the original spelling for display and compare on the folded identity.

What counts as a burn?

UNIVERSE
Legacy position

The legacy material defines no burn rule, and earlier documentation advised showing recovery actions as potentially allocation-destroying rather than as settled burns.

Current implementation

Burning is defined precisely and is a consequence of transaction shape, not an instruction: satoshis paid as fees, sent to an unsupported output, or split so no whole unit fits are burned, and the supply accounting records it.

Resolution

Resolved as a derived outcome. There is still no way to express "burn this" as a message. You burn by constructing a transaction that drops the satoshis.

Does output order matter?

UNIVERSE
Legacy position

Earlier documentation listed output ordering as an open question.

Current implementation

Order matters completely. Allocation is positional: inputs and outputs are concatenated into satoshi ranges in index order, so moving an output changes which units land where.

Resolution

Resolved: build outputs deliberately and test the exact ordering your builder produces. Reordering outputs is never cosmetic.

Is there one official DUST-20 indexer API?

UNRESOLVED
Legacy position

No API schema, pagination model, or response versioning is published in the legacy guide.

Current implementation

The production indexer exposes its own normalized and legacy routes with bearer authentication, stable cursors and explicit coverage labels, but these are one service’s contract.

Resolution

Unresolved as a standard. Validate remote responses against a schema you control and treat coverage, source identity and observation height as part of every answer.

R.8 Open questions

Questions with no authoritative answer. They are listed rather than invented, with the posture that keeps you safe while they stay open.

Do independent implementations agree with these rules?

Why it matters. Most of the transfer, burn and ticker-identity behaviour on this site is settled by one production implementation rather than by a multi-party specification.

Safe posture. Treat rules marked UNIVERSE as a working profile. Before relying on them across tools, test against the specific reader your users will see.

How many confirmations make a DUST-20 balance safe to act on?

Why it matters. The protocol defines no threshold, and reorg handling restores or removes allocations depending on depth.

Safe posture. Publish your own finality depth, show confirmation counts to users, and never present unconfirmed DUST-20 state as settled.

What is the pending lifecycle for an unconfirmed DUST-20 movement?

Why it matters. The production indexer reports partial coverage precisely because it has no exhaustive mempool feed with stable pending and disappearance handling.

Safe posture. Do not build balance guarantees on mempool state. Show pending movements as unverified and re-check at confirmation.

What happens to DUST-20 state when a transaction is replaced?

Why it matters. Replace-by-fee can change the output layout, which changes where colored satoshis land, so a replacement can burn units the original preserved.

Safe posture. Re-derive allocation from the transaction that actually confirmed. Never carry forward the pre-replacement interpretation, and never blindly rebroadcast.

What would a typed authoritative ownership resolver look like?

Why it matters. This is the exact blocker recorded against DUST-20 marketplace mutations: a boolean "is this output still good" answer cannot prove amount, owner, schema, freshness or settlement authority.

Safe posture. A resolver has to return the identity, the exact amount, the owning address, the outpoint, the observation height and the coverage label, and it has to be first-party. Until one exists, DUST-20 stays read-only in Bitcoin Universe products.