Enregistrements de décision · ADR-007
ADR-007: Lineage through an atomic transform operation
Split, merge and processing are one operation, transform, which burns inputs, mints outputs, records their parents on-chain and emits one event that maps to an EPCIS TransformationEvent.
- Identifiant du document
- ADR-007
- Date
- 2026-09-21
- Source
- docs/adr/ADR-007.md
| Field | Value |
|---|---|
| ID | ADR-007 |
| Subject area | Traceability |
| Status | Accepted |
| Date | 2026-09-21 |
| Owners | A-REX Contributors |
| Related requirements | FR-04 (SDD §3) |
| Supersedes / superseded by | — (amended 2026-10-20, see Amendment) |
Context
Lots become other lots: a truckload is split between buyers, silos are merged, wheat is milled into flour. FSMA 204's transformation critical tracking event and GS1 EPCIS 2.0's TransformationEvent both link inputs to outputs with quantities. The earlier design had a PROCESSED state but no way to create the processed lot, and its documentation described parent mappings that did not exist in the code.
Issue
How does a token record that one lot became another, so that recalls and mass-balance audits can follow it?
Assumptions
- Regulators and buyers ask for input-to-output links with quantities.
- Re-batching by holders is routine and should not need an institution.
Constraints
- The link must be atomic with the balance changes.
- Hooks must be able to see and govern the operation.
Alternatives considered
| Alternative | For | Against | Outcome |
|---|---|---|---|
An administrative setParent mapping | Simple | Not atomic, no quantities, can be forged after the fact | Rejected |
Separate split, merge and process functions | Explicit | Three functions and events for one operation with different cardinalities | Rejected |
One transform(from, to, inputIds, inputAmounts, outputs, outputAmounts, processRef) | Atomic, quantified, one event, one EPCIS mapping | Callers build arrays | Accepted |
Decision
transform burns the inputs from from and mints the outputs to to in one transaction, records parentsOf(output) = inputIds, emits one BatchTransformed, and runs every hook with OP_TRANSFORM on each leg. In the reference, a re-batch (same commodity and unit, Σ inputs = Σ outputs) needs only ownership or approval; any other transformation also needs TRANSFORMER_ROLE.
Argument
Making lineage an operation rather than a record means it cannot be written without the units actually moving, and it gives indexers one event per transformation instead of a reconstruction from transfers.
Consequences
Positive
- A recall walks
parentsOfbackwards andBatchTransformedforwards. - Holders can split and merge without waiting for an institution.
Negative
- The standard does not enforce quantity conservation for processing, because yields vary; that is a policy of the reference and of hooks.
Obligations it creates
- Processors hold
TRANSFORMER_ROLE; yield rules, if any, are hooks.
Implementation and evidence
| What | Where |
|---|---|
| Operation | ARexToken.transform, _isRebatch |
| Split, merge, processing, role | test/standard/ARexToken.test.js: splits a batch without any role…, merges two batches into one, processing into another commodity requires TRANSFORMER_ROLE |
| Executed walkthrough and lineage graph | test/standard/ImplementationGuide.test.js |
Amendment 2026-10-20: re-batching keeps goods with the holder
The sections above are the decision as recorded on 2026-09-21 and are left unchanged. This amendment narrows one part of it.
What changed. The Decision said that in the reference implementation a re-batch (same commodity and unit, Σ inputs = Σ outputs) needs only ownership or approval. That allowed a holder to re-batch with to set to another account. Both legs of a transform run hooks with OP_TRANSFORM, so hooks that gate only OP_TRANSFER (AttestationHook, DeliveryHook) never saw the hand-over: a holder could deliver unattested lots, or lots locked for a delivery, to a buyer in one call. The same assumption ("re-batching by holders is routine") holds for re-lotting one's own goods, not for handing them to someone else.
Amended rule (reference implementation, arex-contracts commit f71d808 on branch fix/op-context-reentry). Without TRANSFORMER_ROLE, a re-batch is allowed only when to == from. Delivering the outputs of any transform to another account requires TRANSFORMER_ROLE. A holder who wants to split and sell re-lots in place and then transfers, which runs every OP_TRANSFER rule. A related fix (arex-contracts commit 8313698, same branch) makes DeliveryHook reject OP_BURN and the burn leg of OP_TRANSFORM that would take a holder below its locked units, so a lock cannot be escaped by burning or re-lotting in place.
Standard. The interfaces and the MUST text of AREX-CORE.md §3.4 are unchanged: msg.sender must still be from or its approved operator, and implementations may require stronger authorization. AREX-CORE.md 2.1.0-alpha.0 §8 makes the to == from rule RECOMMENDED ("Re-batching to another holder") and asks hooks that lock units to also gate burns and the burn leg of OP_TRANSFORM ("Locks, burns and re-lotting in place"). Making the rule a MUST is deferred to a 3.0 major version and is the owner's decision; it is also raised as an open question for the ERC review.
Consequences.
- Positive: every movement of goods between holders without a privileged role is an
OP_TRANSFER, so transfer rules cannot be bypassed through lineage. - Negative: a holder can no longer split and deliver in one transaction; it takes a
transformand a transfer. Processors that deliver outputs directly to a buyer needTRANSFORMER_ROLE.
Evidence. test/standard/ARexToken.test.js in arex-contracts: a re-batch to another account requires TRANSFORMER_ROLE, also for an approved operator, a TRANSFORMER_ROLE holder may re-batch to another account, re-batching cannot deliver goods past hooks that gate OP_TRANSFER. Background in the security note on operation context in arex-contracts (docs/SECURITY-NOTE-op-context.md).