Conformance vectors
The deterministic cases that back the prose, the interactive tools, and the tests, all executed from one engine.
Protocol behavior Verified 2026-08-31
Describes the Atomicals protocol itself at the pinned reference revision. It does not promise that any product exposes it.
- Page ID
-
reference/conformance - Normative authority
- Executed source code at a pinned revision
- Networks
- mainnet
- Documentation version
- 2026.08
- Audience
- developer, integrator
- Owner
- bitcoin-universe-docs
- Sources
-
- Atomicals ElectrumX
at
v1.5.2.0the engine is implemented from this revision - Atomicals ElectrumX
at
v1.5.2.0 - Atomicals ElectrumX
at
v1.5.2.0
- Atomicals ElectrumX
at
- Known limitations
-
- The allocation engine models normal allocation and the activation gated custom coloring path. It is explanatory and never a substitute for validating a concrete transaction against your target validator revision.
- Vectors for lifecycle behavior that depends on a live chain or a live service are described here as expectations rather than published as executed vectors, because executing them would require infrastructure this documentation deliberately does not carry.
One engine, three consumers
Section titled “One engine, three consumers”| Artefact | Path |
|---|---|
| Engine | conformance/allocation.mjs |
| Vectors | conformance/vectors/arc20-allocation.json |
| Tests | tests/conformance-allocation.test.mjs |
The engine is implemented directly from assign_expected_outputs_basic,
calculate_outputs_to_color_for_ft_atomical_ids, and
AtomicalsTransferBlueprintBuilder.color_ft_atomicals_regular at the pinned revision.
Executed allocation vectors
Section titled “Executed allocation vectors”Every row below is computed at build time by that engine.
| Case | Coloured inputs | Result per output | Burned | Clean |
|---|---|---|---|---|
Clean split into two outputs clean-split | 1200 units at input 0 | out 0: 700 sats to 700 units; out 1: 500 sats to 500 units | none | yes |
Oversized next output burns the remainder oversized-next-output | 1200 units at input 0 | out 0: 700 sats to 700 units; out 1: 546 sats to 0 units | 500 units of TOKENA | no |
Whole lot into one output exact-single-output | 10000 units at input 0 | out 0: 10000 sats to 10000 units | none | yes |
First output larger than the whole lot first-output-too-large | 500 units at input 0 | out 0: 20000 sats to 0 units | 500 units of TOKENA | no |
Outputs run out before the value does too-few-outputs | 1200 units at input 0 | out 0: 700 sats to 700 units | 500 units of TOKENA | no |
Unspendable outputs are skipped, not funded unspendable-output-skipped | 1200 units at input 0 | out 0: 0 sats (unspendable) to 0 units; out 1: 700 sats to 700 units; out 2: 500 sats to 500 units | none | yes |
Combining two lots of the same token combine-two-lots | 700 units at input 0, 500 units at input 1 | out 0: 1200 sats to 1200 units | none | yes |
Two different tokens take sequential output slots two-tokens-sequential-slots | 700 units at input 0, 900 units at input 1 | out 0: 700 sats to 700 units; out 1: 900 sats to 900 units | none | yes |
A non-clean slot triggers the output zero fallback two-tokens-non-clean-fallback | 700 units at input 0, 400 units at input 1 | out 0: 700 sats to 700 units; out 1: 546 sats to 0 units | 400 units of TOKENB | no |
A remainder smaller than the change output burns dust-remainder-burns | 1200 units at input 0 | out 0: 1000 sats to 1000 units; out 1: 200 sats to 200 units | none | yes |
A change output larger than the remainder burns it change-output-too-large | 1200 units at input 0 | out 0: 1000 sats to 1000 units; out 1: 546 sats to 0 units | 200 units of TOKENA | no |
Custom coloring assigns a partial value to the last output custom-coloring-partial-fill | 1200 units at input 0 | out 0: 700 sats to 700 units; out 1: 546 sats to 500 units | none | no |
Exact single output, exact-cover era suite-exact-single-output | 11000 units at input 0 | out 0: 11000 sats to 11000 units | none | yes |
Partially coloured output, current era suite-partially-colored-carry-forward | 500 units at input 0 | out 0: 11000 sats to 500 units | none | no |
Eleven inputs consolidated into one small output suite-consolidation-burn | 1000 units at input 0, 1000 units at input 1, 1000 units at input 2, 1000 units at input 3, 1000 units at input 4, 1000 units at input 5, 1000 units at input 6, 1000 units at input 7, 1000 units at input 8, 1000 units at input 9, 1000 units at input 10 | out 0: 1000 sats to 1000 units | 10000 units of TOKENA | no |
One satoshi short destroys the whole balance suite-output-over-balance | 10999 units at input 0 | out 0: 11000 sats to 0 units | 10999 units of TOKENA | no |
One unit over the output value burns that unit suite-one-unit-over | 11001 units at input 0 | out 0: 11000 sats to 11000 units | 1 units of TOKENA | no |
Two lots merged into one output, one unit as fee suite-merged-inputs-single-output | 900 units at input 0, 555 units at input 1 | out 0: 1454 sats to 1454 units | 1 units of TOKENA | no |
A transaction carrying no tokens suite-no-atomicals | out 0: 1000 sats to 0 units | none | yes | |
Paying the fee out of coloured value burns it fee-taken-from-colored-value | 10000 units at input 0 | out 0: 3000 sats to 3000 units; out 1: 6800 sats to 6800 units | 200 units of TOKENA | no |
No output able to take colour only-unspendable-outputs | 5000 units at input 0 | out 0: 0 sats (unspendable) to 0 units | 5000 units of TOKENA | no |
Split skips a satoshi amount before colouring split-skip-amount | 3000 units at input 0 | out 0: 1000 sats to 0 units; out 1: 2000 sats to 2000 units | 1000 units of TOKENA | no |
Custom colouring clamps an over-request custom-color-over-request-clamped | 1000 units at input 0, 1000 units at input 0 | out 0: 1200 sats to 1000 units; out 1: 600 sats to 600 units; out 2: 600 sats to 400 units | none | no |
Custom colouring burns what the payload does not place custom-color-unassigned-value-burns | 1000 units at input 0 | out 0: 1000 sats to 400 units; out 1: 500 sats to 0 units | 600 units of TOKENA | no |
What each vector proves
Section titled “What each vector proves”| Case | Proves |
|---|---|
clean-split |
An exactly covered output set places everything with no burn |
oversized-next-output |
An output larger than the remaining value stops the walk and burns the remainder |
exact-single-output |
A single output equal to the value takes everything |
first-output-too-large |
Nothing can be placed at all, so the whole lot burns |
too-few-outputs |
Running out of outputs burns what is left |
unspendable-output-skipped |
An unspendable output is passed over and consumes nothing |
combine-two-lots |
Two inputs of the same token are summed before allocation |
two-tokens-sequential-slots |
A second token starts after the last slot the first used |
two-tokens-non-clean-fallback |
A non-clean plan restarts every token from output zero |
dust-remainder-burns |
A correctly sized change output places the remainder cleanly |
change-output-too-large |
The same intent with a larger change output destroys the remainder |
custom-coloring-partial-fill |
Activation gated custom coloring fills the last output partially instead of burning |
The no-inflation property
Section titled “The no-inflation property”A separate test asserts, across every vector, that coloured output totals never exceed coloured input totals. That is the one rule no output arrangement can work around.
Coverage the vectors do not claim
Section titled “Coverage the vectors do not claim”This documentation does not publish unexecuted vectors as evidence. The following behaviors are documented as expectations, with their source, rather than presented as executed conformance material:
| Behavior | Where it is documented | Why it is not an executed vector here |
|---|---|---|
| Direct FT issuance, DFT deployment, DMT claim validity | ARC-20 | Validity depends on chain height, quota state, and Bitwork at execution time |
| NFT normal transfer, swap, splat | NFT transfers | Requires the non-fungible allocation branch against a live provider |
| Container and DMINT verification | Item verification | Requires a sealed manifest and a live provider |
| Realm candidate and winner resolution | Candidates and winners | Resolution is computed at a chain position |
| Unicode and IDNA behavior | Unicode and IDNA | Enforced by the runtime, surfaced through its explicit errors |
| Marketplace listing, reservation, purchase, settlement, replay, stale ownership, mixed collateral | Marketplace v1 | Enforced by the authority against Bitcoin Core and the Atomicals provider, and covered by that repository’s own suite |
| Media digest validation, reorg generation behavior, signed cursor validation | NFT and Realm API | Enforced by the runtime and covered by that repository’s own suite |
| Ordex purchase and burn vectors | Ordex | Published and executed in the Ordex repository. Copying them here would create a second version that can drift |
Stating this plainly is the point. A vector that was never executed is not evidence.
Adding a vector
Section titled “Adding a vector”See conformance vectors. A new case must name the source lines it derives from, and it must pass before it is committed.