Whitepaper · 07
Хуки и эталонные модули
Как функциональность добавляется к конформному токену без изменения стандарта: контракт хука, эталонные хуки, сопутствующие расширения и способы написать, протестировать и зарегистрировать собственный хук.
Модули — это демонстрации, а не стандарт
Отношение между A-REX Core и его модулями такое же, как между ERC-3643 и модулями комплаенса T-REX: интерфейс, через который подключаются модули, стандартизирован; модули — нет. Конформный токен без хуков является допустимым токеном A-REX. Хук, написанный кем угодно, совместим с любым конформным токеном. Именно это позволяет экосистеме расти без изменения стандарта.
graph LR
T["ARexToken<br/>конформный токен"] -->|"check / onExecuted / canSend / canReceive"| H1[EligibilityHook]
T --> H2[ExpiryHook]
T --> H3[AttestationHook]
T --> H4["Пользовательский хук"]
H3 --> A[ARexAttestations]Контракт хука
| Обратный вызов | Когда | Должен |
|---|---|---|
check | до изменения балансов, для каждого затронутого id, хуки в порядке регистрации, остановка на первом ненулевом значении | быть view-функцией; никогда не откатываться из-за политики |
onExecuted | после изменения балансов, для каждого id, по порядку | не вызывать функции токена, изменяющие баланс (токен заблокирован) |
canSend / canReceive | при каждом переводе и для view-функций ERC-7943 токена | быть view-функциями |
op принимает одно из значений OP_MINT (1), OP_TRANSFER (2), OP_BURN (3), OP_FORCED_TRANSFER (4), OP_TRANSFORM (5). В преобразовании входы приходят с to == 0, а выходы — с from == 0. data — это данные перевода ERC-1155, abi.encode(processRef) для преобразований и пусто для принудительных переводов.
Вызывающий токен — это msg.sender. Хук, которому нужна партия, читает IARexBatch(msg.sender).batchOf(id).
Эталонные хуки
EligibilityHook — разрешение, блокировка, санкции
Демонстрирует HOOK_ELIGIBILITY. Ведёт необязательный список разрешённых адресов, список заблокированных адресов и санкционный список; canSend/canReceive возвращают их конъюнкцию; check возвращает SANCTIONED, SENDER_INELIGIBLE или RECEIVER_INELIGIBLE, чтобы интерфейсы могли объяснить отказ. Принудительные переводы разрешены всегда: изъятие товара со счёта, попавшего под санкции, и есть смысл принудительного исполнения. В промышленной эксплуатации списки наполняются из реестра идентичности (ONCHAINID, EAS, верифицируемые учётные данные) или санкционного оракула; хуку безразлично, из какого.
ExpiryHook — скоропортящесть без отдельного модуля
Не хранит состояния. Читает expiresAt и producedAt из партии. Блокирует эмиссию и переводы просроченных партий (BATCH_EXPIRED), но не сжигание (списание) и не принудительные переводы (принудительное исполнение). Опционально блокирует переводы ещё не произведённых партий (BATCH_NOT_PRODUCED): платформа, финансирующая до уборки урожая, устанавливает флаг так, чтобы разрешать их; спотовая торговая площадка — так, чтобы блокировать. Этот единственный хук покрывает блокирующую часть скоропортящести; кривые порчи становятся вспомогательной view-функцией или офчейн-оценкой.
AttestationHook — регуляторные ограничения по товарам
Сопоставляет код товара с обязательной темой аттестации. Перед переводом читает партию, находит требование, запрашивает у реестра аттестаций isAttested и в противном случае возвращает ATTESTATION_MISSING. Правила «кофе нужна ссылка на должную осмотрительность по EUDR», «партиям с маркировкой органической продукции нужен действующий сертификат органической продукции», «скоту нужен санитарный сертификат» — это по одному вызову setRequirement каждое.
PerishabilityHook — модели порчи
Конфигурация порчи по коду товара с переопределением для отдельной партии; модели NONE, LINEAR (до нижнего порога к моменту истечения срока), EXPONENTIAL (период полураспада) и STEP (ступенчатое снижение через каждый интервал). View-функции valueBps, secondsRemaining, isExpired. Блокирует эмиссию и переводы просроченных партий (BATCH_EXPIRED) и переводы партий, остаточная стоимость которых равна нулю (PERISH:NO_VALUE); никогда не блокирует сжигание или принудительное исполнение.
SeasonalHook — окна сбора урожая и торговли
Абсолютные окна [start, end] по товару и операции (не более 16 на ключ). Сочетание товара и операции без окон не ограничено. Типичное использование: OP_MINT ограничивается окном сбора урожая, OP_TRANSFER — окном торговли; в остальных случаях возвращается SEASON_CLOSED.
DeliveryHook — хранение и расчёты
Отправитель планирует доставку amount единиц получателю через перевозчика; единицы блокируются (счётчик O(1), поэтому check никогда не перебирает историю). Перевозчик и датчики фиксируют забор груза, транзит и показания температуры (флаг нарушения); получатель подтверждает доставку; споры передаются арбитру. Расчёт — это сам перевод ERC-1155: отправитель → получатель, точное количество, с data = abi.encode(deliveryId); check разрешает его только тогда, когда доставка находится в состоянии DELIVERED, а onExecuted переводит её в SETTLED и снимает блокировку. Свободные (неблокированные) единицы продолжают перемещаться.
TraceabilityHook — журнал событий в форме EPCIS
Наблюдает за каждой операцией токена и классифицирует её по бизнес-шагам CBV (commissioning, shipping, destroying, transforming) и состояниям (active, in_transit, destroyed, seized); RECORDER_ROLE записывает критические события отслеживания, не связанные с токеном (охлаждение, упаковка, приёмка), с readPoint и bizLocation. Два режима: только генерация событий (около +17 k газа на перевод; индексатор восстанавливает журнал) или сохранение (около +184 k; getEvents отвечает ончейн, постранично).
Сопутствующие расширения
Три задачи никогда не требовали оформления в виде правил перевода; это обычные контракты, которые читают или записывают аттестации:
| Расширение | Что делает |
|---|---|
CommodityPriceOracle | репортёры передают цены по товарам; раунды нумеруются и финализируются по кворуму с медианой либо вручную по достижении минимума; latestAnswer, isStale |
CarbonImmobilizationWrapper | фиксирует кредиты, иммобилизованные в реестре (реестр, диапазон серийных номеров, винтаж, тонны, доказательство), связывает тонны с партиями, отражает погашение и высвобождение, записывает аттестацию AREX:CARBON:IMMOBILIZED; никогда не эмитирует кредиты |
ParametricInsurance | пул ERC-20; полис на партию с темой-триггером; страховое требование выплачивается, когда триггер аттестован до истечения срока |
Написание собственного хука
Пример contracts/examples/SeasonHook.sol остаётся в репозитории. test/standard/ImplementationGuide.test.js проверяет его для читателей с доступом. SeasonalHook — эталонный модуль для нескольких окон на товар и на операцию.
Практические правила:
- Символы
OKиOP_FORCED_TRANSFERопределены в нормативном тексте. - Поведение сжигания определено в нормативном тексте.
- Обратный вызов
checkопределён в нормативном тексте. - Имена кодов, такие как
ARexCodes.code("MYNS", "NAME"), определены в нормативном тексте. - Значения флагов определены в нормативном тексте.
- Обратные вызовы
onExecutedиcheckопределены в нормативном тексте.
Регистрация и порядок
Дешёвые правила с высокой долей отказов следует ставить первыми. HOOK_ADMIN_ROLE следует размещать за мультиподписью или таймлоком: тот, кто контролирует конвейер, контролирует, какие переводы возможны.
Тестирование
test/standard/helpers.js развёртывает эталонный стек. RecordingHook записывает каждый обратный вызов и может получить указание отклонять с любым кодом; ReentrantHook пытается повторно войти в токен из onExecuted и подтверждает работу блокировки. DomainHooks.test.js и Extensions.test.js покрывают перенесённые хуки и сопутствующие контракты; Invariants.test.js выполняет случайную последовательность операций с зафиксированным seed и проверяет сохранение предложения, терминальность статуса и то, что canTransfer предсказывает каждый исход.
Взаимодействие с комплаенсом ERC-3643
Модуль комплаенса ERC-3643 предоставляет moduleCheck(from, to, value, compliance). Хук, который вызывает его для OP_TRANSFER и сопоставляет false с кодом, делает ограничения по странам, лимиты баланса и временные блокировки, написанные для токенов-ценных бумаг, пригодными для повторного использования на токенах партий. Обратное — предоставление хука A-REX токену ERC-3643 — столь же механично. Chainlink Automated Compliance Engine интегрируется по тому же шаблону: его движок политик становится одним хуком.