Whitepaper · 04
Обзор решения
Архитектура A-REX Core: три яруса с единым направлением зависимости, конвейер переводов, участники и способы развёртывания компонентов.
Три яруса, одно направление зависимости
A-REX отделяет то, что должно быть стандартизировано, от того, что должно просто работать:
Четыре уровня стандарта
flowchart TB
L3["Уровень 3 · IARexAttest<br/>attest · revokeAttestation · isAttested · доверенные эмитенты по темам"]
L2["Уровень 2 · IARexHook + IARexHookManager<br/>hookFlags · check → bytes32 · onExecuted · getHooks"]
L1["Уровень 1 · IARexBatch<br/>createBatch · batchOf · setBatchStatus · setBatchMetadata · transform · parentsOf"]
L0["Уровень 0 · ERC-1155 + ERC-165 + IERC7943MultiToken<br/>freeze · forcedTransfer · canSend · canReceive · canTransfer"]
L3 --- L2 --- L1 --- L0
classDef l3 fill:#edf5ff,stroke:#0f62fe,color:#161616
classDef l2 fill:#d0e2ff,stroke:#0f62fe,color:#161616
classDef l1 fill:#a6c8ff,stroke:#0f62fe,color:#161616
classDef l0 fill:#78a9ff,stroke:#0043ce,color:#161616
class L3 l3
class L2 l2
class L1 l1
class L0 l0Два яруса репозитория и направление зависимости
flowchart LR
STD["<b>Стандарт</b><br/>standard/ · contracts/standard/<br/>нормативный · CC0"]
REF["<b>Эталонная реализация</b><br/>ARexToken · ARexAttestations<br/>MIT"]
DEMO["<b>Демонстрации</b><br/>7 хуков · 3 расширения<br/>MIT · не нормативны"]
STD -->|реализуется в| REF -->|демонстрируется в| DEMO
DEMO -.->|зависят только от интерфейсов| STDСтандарт никогда не зависит от эталонной реализации; токен никогда не зависит от хуков. Если убрать все хуки и все расширения, конформный токен всё равно остаётся. Именно это свойство позволяет третьей стороне реализовать A-REX, не принимая из этого репозитория ничего, кроме шести файлов интерфейсов.
Что такое партия
Партия — это идентификатор токена ERC-1155 с записью:
struct Batch {
address issuer; // who created it (or performed the transformation)
uint64 createdAt;
uint8 status; // 0 ACTIVE · 255 RETIRED (terminal) · 1..254 issuer-defined
bytes32 commodity; // keccak256("HS:100199"), keccak256("FAO:0111"), keccak256("GTIN:0779…")
bytes32 unit; // UN/CEFACT Rec. 20: "KGM", "TNE", "LTR", "BX"
uint64 producedAt; // 0 = not yet produced (pre-harvest)
uint64 expiresAt; // 0 = none
bytes32 originRef; // hash / reference to origin evidence — never coordinates
bytes32 metadataHash; // keccak256 of the off-chain document
string uri; // where the document is
}
Всё более подробное — класс качества, влажность, белок, упаковка, идентификаторы GS1, код лота прослеживаемости, ссылка на декларацию EUDR, лабораторные отчёты, таблица статусов эмитента — находится в документе метаданных, хеш которого зафиксирован ончейн. Документ соответствует опубликованной JSON Schema, согласованной с EPCIS 2.0 и ключевыми элементами данных FSMA 204.
Конвейер переводов
Каждое изменение баланса — эмиссия, перевод, сжигание, принудительный перевод, преобразование — проходит в эталонном токене через единую точку контроля. Порядок зафиксирован и поддаётся аудиту:
flowchart TD
A[safeTransferFrom / createBatch / burn / forcedTransfer / transform] --> B["блокировка реентерабельности"]
B --> C{"приостановлено?"}
C -- да, не принудительный --> X1[EnforcedPause]
C -- нет --> D{"canSend отправителя / canReceive получателя<br/>конъюнкция хуков ELIGIBILITY"}
D -- false --> X2[ERC7943CannotSend / CannotReceive]
D -- true --> E{"для каждого id: существует? не погашена?<br/>количество ≤ баланс − заморожено?"}
E -- ошибка --> X3[ARexBatchNotFound / ARexBatchRetired /<br/>ERC7943InsufficientUnfrozenBalance]
E -- успешно --> F{"для каждого id и каждого хука CHECK по порядку:<br/>check → код"}
F -- код ≠ 0 --> X4["ARexHookRejected(hook, code)"]
F -- все 0 --> G["балансы обновлены · предложение учтено"]
G --> H["для каждого id и каждого хука EXECUTED: onExecuted"]
H --> I["разблокировка"]Две view-функции воспроизводят ту же логику без изменения состояния: canTransfer (булево значение, как требует ERC-7943) и transferCheck (первый код отказа, чтобы интерфейс мог сообщить пользователю, почему).
Принудительные переводы пропускают проверки приостановки и допуска — принудительное исполнение должно работать, когда всё остальное заморожено, — но всё равно запускают хуки с OP_FORCED_TRANSFER, поэтому хук может, например, требовать в данных перевода ссылку на судебное постановление.
Родословная
transform — единственная операция для разделения, объединения и переработки:
graph LR
W1["пшеница #1<br/>250 т · фермер"] -- "transform (переформирование)" --> W2["пшеница #2<br/>100 т · покупатель A"]
W1 -- "transform (переформирование)" --> W3["пшеница #3<br/>150 т · покупатель B"]
W2 -- "transform (переработка, TRANSFORMER_ROLE)" --> F4["мука #4<br/>75 т · мельница"]- Переформирование партий (тот же товар, та же единица измерения, сохранённое количество) доступно любому держателю или одобренному оператору: кооператив делит лот из силоса между участниками, экспортёр объединяет поставки.
- Переработка (всё остальное) дополнительно требует
TRANSFORMER_ROLE. parentsOf(4) == [2],parentsOf(2) == [1]; одно событиеBatchTransformedна операцию, являющееся по построению EPCISTransformationEvent.
Принудительное исполнение
ENFORCER_ROLE может заморозить любое количество для любого аккаунта (setFrozenTokens, количество может превышать баланс, как определяет ERC-7943) и переместить токены без согласия держателя (forcedTransfer). Именно это делает токен партии пригодным для использования за пределами демонстрации: кредитор, реализующий права по варранту, суд, предписывающий арест хранящегося зерна, склад, возвращающий лот после того, как клиент потерял ключи. Каждое действие принудительного исполнения — это событие.
Хуки
Хук — это контракт с пятью функциями и константной битовой маской флагов. Токен кэширует флаги при регистрации, поэтому перевод обходится в один внешний вызов на каждый заинтересованный хук, а не в один опрос интерфейса на каждую возможность каждого модуля. Хук узнаёт, какой токен его вызывает, из msg.sender; одно развёртывание может обслуживать много токенов.
Эталонные хуки демонстрируют три возможности:
| Хук | Возможность | Что показывает |
|---|---|---|
EligibilityHook | CHECK + ELIGIBILITY | списки разрешённых и заблокированных адресов и санкционные данные питают canSend / canReceive и дают точные коды |
ExpiryHook | CHECK | скоропортящесть и ограничение операций до уборки урожая, выводимые исключительно из записи партии |
AttestationHook | CHECK | «кофе требует декларации EUDR, аттестованной до того, как его можно продать» |
PerishabilityHook | CHECK | модели порчи и view-функции стоимости; просроченные лоты и лоты, лишённые стоимости, не перемещаются |
SeasonalHook | CHECK | окна сбора урожая и торговли по товарам |
DeliveryHook | CHECK + EXECUTED | блокировка хранения на время доставки; расчёт — это сам перевод, идентифицируемый по data |
TraceabilityHook | EXECUTED | журнал событий в форме EPCIS для каждой операции плюс ручные критические события отслеживания |
Сопутствующие расширения (не хуки): CommodityPriceOracle, CarbonImmobilizationWrapper, ParametricInsurance.
Аттестации
Сопутствующий контракт записывает (batch, topic) → (issuer, reference, validity). Аттестовать могут только эмитенты, которым доверяют по данной теме; отзыв, истечение срока и утрата доверия делают isAttested ложным. Темы имеют тип bytes32, поэтому темы утверждений ERC-735, идентификаторы схем Ethereum Attestation Service и хеши названий сертификаций работают без таблицы в стандарте.
Участники и роли
| Участник | Типичная роль в эталонном токене | Типичное действие |
|---|---|---|
| Платформа-инициатор, кооператив, элеватор | ISSUER_ROLE | createBatch |
| Фермер / держатель | нет | перевод, переформирование партий, сжигание |
| Мельница, фасовщик, переработчик | TRANSFORMER_ROLE | transform для переработки |
| Склад, инспектор, платформа | STATUS_ROLE | setBatchStatus, setBatchMetadata |
| Сертификатор, лаборатория, орган власти | доверенный эмитент по теме | attest |
| Кредитор, назначенный судом хранитель, комплаенс | ENFORCER_ROLE | setFrozenTokens, forcedTransfer |
| Управление (мультиподпись, таймлок) | DEFAULT_ADMIN_ROLE, HOOK_ADMIN_ROLE, UPGRADER_ROLE, PAUSER_ROLE | роли, хуки, обновления, приостановка |
Ничто в стандарте не фиксирует эти роли; так эталонная реализация выполняет требования уровня «ДОЛЖЕН» («ограничено уполномоченной ролью»).
Варианты развёртывания
- Публичная сеть L2 (Polygon, Arbitrum, Base, Optimism): самая дешёвая и наиболее композируемая; подходит для торговли товарами и финансирования, где контрагенты — организации.
- Сеть EVM с разрешительным доступом: там, где этого требуют органы по защите данных или якорное учреждение; EDPB прямо поощряет архитектуры с разрешительным доступом. Стандарт не привязан к конкретной сети.
- Гибридный вариант: партии в публичной сети, а данные с ограниченным доступом (полигоны участков, идентичность производителя) — в хранилище с контролем доступа, на которое ссылаются метаданные.
Эталонный стек развёртывается одним модулем Ignition или одним скриптом: прокси токена, реестр аттестаций, хуки допуска и срока годности.
Проектные решения и заменяемые ими альтернативы
| Рассмотренная альтернатива | A-REX Core | Причина |
|---|---|---|
| широкий интерфейс ядра с перечислениями для товара, класса качества, состояния | IARexBatch из 8 функций с открытыми кодами | не нужно ничего развёртывать повторно ради новой культуры, схемы или жизненного цикла |
| интерфейсы возможностей, опрашиваемые при каждом переводе | один интерфейс хука, флаги кэшируются | газ линеен по числу хуков, а не по произведению id × модули × опросы |
| строковые причины | коды bytes32 и типизированные ошибки | машиночитаемость, индексируемость |
| состояние жизненного цикла, изменяемое любым держателем | только роль; RETIRED терминален | безопасность |
| дата сбора урожая обязана лежать в прошлом | допускается producedAt == 0 | финансирование до уборки урожая |
| нет разделения, объединения и переработки | transform + parentsOf | прослеживаемость, отзывы, EPCIS |
| нет заморозки и принудительного перевода | ERC-7943 | возможность принудительного исполнения |
| координаты хранятся ончейн | только ссылка на происхождение | GDPR / EDPB 02/2025 |
| требуются контракты реестра и идентичности | ничего не требуется | никакого навязанного стека идентичности |