Skip to main contentA-REX Foundation

निर्णय रिकॉर्ड · ADR-023

ADR-023: Several values in one transfer's data, each under its own key

AREX CORE §4 passes the data of an ERC 1155 transfer to every hook, unchanged. Two reference hooks read it, and each gives the same 32 bytes its own meaning: DeliveryHook reads uint256 deliveryId (a transfer settles the

**Proposed** (2026-10-27). Reference hooks available in arex-contracts 2.0.0-alpha.7; informative, adds no requirement to AREX-CORE.md
दस्तावेज़ आईडी
ADR-023
तिथि
2026-10-27
स्रोत
docs/adr/ADR-023.md
केवल अंग्रेज़ी में उपलब्ध
यह पृष्ठ अंग्रेज़ी में है। श्वेतपत्र के अध्याय और आरेख अनूदित हैं। नॉर्मेटिव मानक रिपॉज़िटरी में रहता है; उस पाठ के लिए शीघ्र पहुँच का अनुरोध उपयोग करें। सिस्टम डिज़ाइन मार्गदर्शिकाएँ और निर्णय रिकॉर्ड अंग्रेज़ी में रहते हैं।

When more than one rule reads the data of a transfer, the data is a tagged envelope of (key, value) pairs, each rule reads only its own key, and 32-byte data keeps its single meaning for rules written before the envelope.

FieldValue
IDADR-023
Subject areaExtensibility, hook data
StatusProposed (2026-10-27). Reference hooks available in arex-contracts 2.0.0-alpha.7; informative, adds no requirement to AREX-CORE.md
Date2026-10-27
OwnersA-REX Contributors; requested by the A-REX Platform (lot-rules audit, item K3)
Related requirementsAREX-CORE §4 (data passed to hooks), §5, ADR-004, ADR-005, ADR-019
Supersedes / superseded by—

Context

AREX-CORE §4 passes the data of an ERC-1155 transfer to every hook, unchanged. Two reference hooks read it, and each gives the same 32 bytes its own meaning: DeliveryHook reads uint256 deliveryId (a transfer settles the delivery it names), TraceabilityHook reads bytes32 ref (the document of the movement, such as the hash of an e-CMR or a bill of lading). With both on one token, a transfer can carry only one of them: settling a tracked delivery writes its number as the trace entry's document, and a document reference whose value happens to equal a delivery's number could settle that delivery. The A-REX Platform worked around it outside the ledger (one meaning per transfer, read back in words; a separate trace entry for the document), but every implementer combining rules meets the same problem, and any third rule that reads data adds a third meaning.

Issue

How can several rules read values from the data of one transfer without giving the same bytes two meanings, and without breaking rules already deployed that read 32 bytes?

Assumptions

  • Rules are independent contracts that see the same data (ADR-004); none can strip or rewrite it for the next.
  • Values a rule reads from data are small identifiers or hashes (32 bytes each); documents themselves stay off-chain.
  • Deployed hooks cannot be upgraded (reference hooks are not proxies); a new format reaches them only through new instances.

Constraints

  • AREX-CORE §4: data is passed unchanged; the token does not interpret it.
  • ERC-1155 also passes data to a contract recipient's acceptance callback.
  • Reading must be cheap and bounded (hooks run on every transfer) and must never revert on malformed data.

Alternatives considered

AlternativeForAgainstOutcome
One meaning per transfer, chosen off-chain (status quo)no contract changethe ledger cannot tell which meaning was meant; values collide; each implementer re-solves itRejected as a long-term answer (kept for older instances)
A registry in the token mapping data slices to hooksexplicitchanges the core token and the interfaces; the token would interpret dataRejected
ABI-encoded struct with one field per known rulesimple to decodeclosed set: a new rule needs a new struct; empty fields cost bytesRejected
A tagged envelope of (bytes32 key, bytes32 value) pairs, keys namespaced like codesopen set, like codes (ADR-005, ADR-006); bounded; 32-byte data stays distinctone more convention to documentProposed

Decision (proposed)

The data a hook reads is one of:

  1. 32 bytes: one value, read by each rule with the meaning it had before this record (legacy, unchanged);
  2. a tagged envelope: a non-zero multiple of 64 bytes, at most 8 entries (512 bytes), each entry abi.encode(bytes32 key, bytes32 value) laid end to end;
  3. anything else (empty, other lengths, more than 8 entries): no value for any rule.

Rules:

  • A key is keccak256("<NAMESPACE>:<NAME>"), like a rejection code (ADR-005). Two keys are defined by the reference hooks: keccak256("AREX:DELIVERY_ID") (value: the uint256 number of a tracked delivery, read by DeliveryHook) and keccak256("AREX:DOCUMENT_REF") (value: the bytes32 reference of the movement's document, read by TraceabilityHook). Implementers add keys under their own namespace.
  • A rule reads only its own key, takes the first entry with it, and ignores every other entry. A key SHOULD appear at most once.
  • An envelope is never 32 bytes long, so a rule written before this record reads it as "no value"; a sender MUST NOT send an envelope to a token whose rules that read data do not all read envelopes.
  • Reading never reverts: a malformed envelope is "no value".
  • A value's meaning is the key's, never the rule's, so the same key means the same thing to every rule that reads it.

Argument

The envelope gives each value one meaning on the ledger, so an auditor reading a transfer can tell a delivery number from a document without asking the platform that sent it. It needs no change to the core token or the interfaces, and legacy 32-byte data keeps working because no envelope is 32 bytes long. Keys follow the convention codes already use, so the set stays open without a registry.

Consequences

Positive

  • A tracked delivery's settlement can carry its document in the same transfer; the trace entry keeps the document and the delivery is settled by its number.
  • New rules that read data add a key instead of competing for the same 32 bytes.

Negative

  • Up to 512 bytes of data per transfer (calldata cost), and a short loop per reading rule.
  • Older rule instances read envelopes as "no value"; a sender must know which instances a token runs (a rule descriptor can say so; see interop/RULE-DESCRIPTOR.md).

Obligations it creates

  • A rule that reads data documents which keys it reads and what their values mean.
  • Senders build envelopes only for tokens whose data-reading rules all read them.

Implementation and evidence

WhatWhere
Readerarex-contracts contracts/reference/hooks/ARexTransferData.sol (library: valueOf(data, key), never reverting)
RulesDeliveryHook (AREX:DELIVERY_ID) and TraceabilityHook version 2 (AREX:DOCUMENT_REF), release 2.0.0-alpha.7
Testsarex-contracts test/foundry/TransferDataEnvelope.t.sol: one transfer settles a delivery and records its document; legacy 32-byte data unchanged; malformed envelopes read as no value; fuzzed
First consumerA-REX Platform: a tracked delivery's hand-over with a document, when both rules run 2.0.0-alpha.7
  • ADR-004: every rule is an independent hook that sees the same call
  • ADR-005: namespaced bytes32 codes, the convention keys follow
  • ADR-019: capabilities in the standard, policy in profiles