Skip to main contentA-REX Foundation

Entscheidungsprotokolle · ADR-005

ADR-005: bytes32 rejection codes instead of strings or hook-side custom errors

A hook refuses by returning a namespaced bytes32 code; the token reverts with ARexHookRejected(hook, code) and exposes the same code before the transaction through transferCheck.

Accepted
Dokument-ID
ADR-005
Datum
2026-09-21
Nur auf Englisch verfügbar
Diese Seite ist auf Englisch. Die Kapitel des Whitepapers und die Diagramme sind übersetzt. Der normative Standard bleibt im Repository; nutzen Sie Frühen Zugang beantragen für diesen Text. Leitfäden zum Systementwurf und Entscheidungsprotokolle bleiben auf Englisch.
FieldValue
IDADR-005
Subject areaError model
StatusAccepted
Date2026-09-21
OwnersA-REX Contributors
Related requirementsFR-09 (SDD §3)
Supersedes / superseded by—

Context

A farmer's wallet has to say why a transfer failed, an indexer has to count refusals by reason, and a test has to compare them. Free-form revert strings are expensive, untranslatable and not indexable. If hooks reverted with their own custom errors, a view that asks several hooks, such as canTransfer, could not compose their answers.

Issue

How does a hook communicate a refusal so that the token, user interfaces and indexers can act on it?

Assumptions

  • Front-ends must explain refusals in the user's language.
  • Indexers and tests must compare refusals exactly.

Constraints

  • check must be a view so that pre-flight checks can call it.

Alternatives considered

AlternativeForAgainstOutcome
Free-form revert stringsReadable in explorersCostly, not indexable, not translatable, not composableRejected
Hooks revert with custom errorsTypedcheck could not be composed in a view across hooksRejected
bytes32 codes keccak256("NAMESPACE:NAME"); token reverts with ARexHookRejected(hook, code)Cheap, comparable, indexable, open to new namespacesNeeds a dictionary to show textAccepted

Decision

check returns bytes32; zero means allowed. Codes are keccak256("NAMESPACE:NAME"); the recommended AREX: codes live in ARexCodes. The token reverts with ARexHookRejected(address hook, bytes32 code) and exposes transferCheck, which returns the first code, in the same order as the transaction.

Argument

A 32-byte code is the cheapest value that is both collision-resistant and open to anyone's namespace. Naming the rejecting hook in the error tells an operator which rule to look at without a trace.

Consequences

Positive

  • Wallets can show a translated reason before sending a transaction.
  • Issuers add codes without coordinating with anyone.

Negative

  • Front-ends need a code dictionary; unknown codes show as hashes.

Obligations it creates

  • transferCheck and the transaction evaluate in the same order (regression test).
  • Hooks document their codes.

Implementation and evidence

WhatWhere
Codescontracts/standard/ARexCodes.sol
ErrorIARexHook.ARexHookRejected
Same order in view and transactiontest/standard/ARexToken.test.js: reports eligibility before batch existence, like _update
  • ADR-004: One hook interface, flags cached at registration, ordered evaluation
  • ADR-006: Open codes instead of closed enumerations