Whitepaper · 08
Фреймворк безопасности
Модель угроз, инварианты, управление доступом, граница доверия хуков, управление ключами принудительного исполнения, безопасность обновлений и состояние аудита эталонной реализации A-REX Core.
Профиль безопасности в одном абзаце
У эталонного токена одна точка контроля (_update), фиксированный порядок вычисления, блокировка реентерабельности вокруг всей последовательности хуков, ролевые полномочия, никогда не вытекающие из балансов, хранилище ERC-7201 и небольшая поверхность: восемь внешних функций, изменяющих состояние, помимо ERC-1155. Наиболее мощные возможности — заморозка, принудительный перевод, администрирование хуков, обновления — вынесены в отдельные роли, предназначенные для мультиподписей и таймлоков, и каждое их использование является событием.
Инварианты
| Инвариант | Обеспечивается | Тестируется |
|---|---|---|
totalSupply(id) равно сумме балансов для id | OpenZeppelin ERC1155Supply; transform сжигает, затем эмитирует через _update | тесты родословной (разделение, объединение, переработка) |
status == 255 терминален | setBatchStatus откатывается с ARexInvalidStatusTransition | тесты статусов |
| Погашенную партию нельзя эмитировать или переводить, можно только сжигать | _update | тест погашенной партии |
amount ≤ balance − frozen для перемещений по инициативе держателя | _update; forcedTransfer снижает frozen до balance − amount | тесты заморозки и принудительных переводов |
| Ни один хук не может повторно войти в функцию, изменяющую баланс | блокировка в хранилище устанавливается до проверок и снимается после уведомлений | тест ReentrantHook |
| Хуки вычисляются в порядке регистрации; удаление сохраняет порядок | сдвиг массива в removeHook | тест порядка |
| Отклонённая операция не меняет ни одного баланса и не генерирует перевода | проверки выполняются до super._update | тест отказа (число выполнений не меняется) |
| Полномочия никогда не вытекают из баланса | каждая функция, меняющая состояние, защищена ролью или одобрением ERC-1155 | тесты «владение токенами ничего не даёт» |
canTransfer == (transferCheck == 0) | canTransfer определён именно так | тесты конформности |
Модель угроз
Участники и возможности
| Участник | Может | Не может |
|---|---|---|
| Держатель | переводить незамороженные единицы допущенным получателям; сжигать; переформировывать партии того же товара и единицы измерения с сохранением количества | менять статус, эмитировать, перерабатывать в другой товар, перемещать замороженные единицы |
| Одобренный оператор | то же, что держатель, для одобрившего аккаунта | всё, чего не может держатель |
ISSUER_ROLE | создавать партии | перемещать чужие токены |
TRANSFORMER_ROLE | перерабатывающие преобразования токенов, находящихся у держателя роли или одобренных для него | преобразовывать токены без одобрения |
STATUS_ROLE | менять статус (включая погашение), обновлять метаданные | перемещать токены |
ENFORCER_ROLE | замораживать любое количество; принудительно переводить любые токены | обходить хуки (они выполняются с OP_FORCED_TRANSFER) |
HOOK_ADMIN_ROLE | добавлять и удалять хуки | напрямую менять балансы |
PAUSER_ROLE | останавливать всё, кроме принудительных переводов | — |
UPGRADER_ROLE | заменять реализацию | — (это абсолютная власть; см. управление ключами) |
| Контракт хука | отклонять операции; наблюдать за ними; отвечать о допуске | повторно входить; менять балансы |
Сценарии
Вредоносный или ошибочный хук (отказ в обслуживании). Хук, всегда отклоняющий операции, блокирует все переводы токена; хук, откатывающийся в check, делает то же самое. Снижение риска: HOOK_ADMIN_ROLE может в любой момент удалить любой хук (порядок сохраняется); PAUSER_ROLE может приостановить работу на время расследования; принудительные переводы по-прежнему выполняются, поэтому принудительное исполнение не теряется. Регистрация проверяет поддержку ERC-165 и ненулевые флаги и отклоняет EOA. Рекомендация: проводить аудит хуков до регистрации; сохранять их число небольшим; размещать администратора за таймлоком, чтобы изменения хуков были видны до вступления в силу.
Повторный вход через хук. onExecuted хука обращается обратно к safeTransferFrom. Снижение риска: блокировка; вызов откатывается с ARexReentrantCall. Следует учесть, что обратный вызов получателя ERC-1155 (onERC1155Received) выполняется после снятия блокировки, как в любом токене ERC-1155; к этому моменту состояние токена окончательно.
Компрометация ключа принудительного исполнения. Тот, кто держит ENFORCER_ROLE, может переместить любые токены. Снижение риска: мультиподпись с документированной процедурой (судебное постановление, договор залога, уведомление о санкциях); каждое действие генерирует ForcedTransfer/Frozen; хуки могут требовать ссылку на распоряжение в данных перевода (OP_FORCED_TRANSFER не освобождён от хуков). Для несрочного принудительного исполнения стоит рассмотреть таймлок.
Компрометация ключа обновления. Полная компрометация. Снижение риска: мультиподпись плюс таймлок; проверки обновлений OpenZeppelin в CI; хранилище ERC-7201, исключающее случайные ошибки раскладки.
Злоупотребление статусом. STATUS_ROLE может погасить партию, принадлежащую другим. Это сделано намеренно — склад, инспектор или регулятор объявляет лот непригодным — и должно раскрываться держателям. Снижение риска: назначать подотчётному учреждению; каждое изменение — это событие с указанием причины.
Мошенничество эмитента. ISSUER_ROLE может создать партию, которой физически не существует. Токен не может этому помешать; он делает это прослеживаемым до конкретной стороны (issuer, originRef, metadataHash) и позволяет требовать до перевода аттестаций независимых сторон (склад, инспектор, реестр) через AttestationHook.
Подмена метаданных. setBatchMetadata изменяет хеш и URI. Снижение риска: доступ ограничен ролью; события BatchMetadataUpdated и URI сохраняют историю; более ранние документы остаются проверяемыми по более ранним хешам.
Front-running transferCheck. Предварительная проверка может устареть до исполнения транзакции (состояние хука изменяется). Транзакция вычисляет всё заново; худший случай — откат с точным кодом.
Gas griefing через хуки. Каждый хук добавляет по одному внешнему вызову на каждый затронутый id на каждой фазе. Хук с неограниченными циклами делает переводы непосильными по стоимости. Снижение риска: правила разработки хуков (ограниченный check), проверка перед регистрацией.
Доверие к обновляемым хукам. Хук, развёрнутый за прокси, может изменить политику переводов без каких-либо изменений в токене. Снижение риска: обращаться с административными ключами хука с такой же заботой, как с HOOK_ADMIN_ROLE; для промышленной эксплуатации предпочитать неизменяемые хуки.
Модель управления доступом
OpenZeppelin AccessControl с восемью ролями у токена и одной — у реестра аттестаций; DEFAULT_ADMIN_ROLE администрирует их все. Рекомендуемая схема для промышленной эксплуатации:
| Роль | Держатель |
|---|---|
DEFAULT_ADMIN_ROLE, UPGRADER_ROLE, HOOK_ADMIN_ROLE | мультиподпись управления за таймлоком |
ENFORCER_ROLE | мультиподпись принудительного исполнения (комплаенс + юристы) |
PAUSER_ROLE | ключ реагирования на инциденты (быстрый) |
ISSUER_ROLE, STATUS_ROLE, TRANSFORMER_ROLE | операционные сервисы с минимальными привилегиями, с ротацией ключей |
ATTEST_ADMIN_ROLE | сертифицирующий орган или платформа |
initialize из соображений удобства выдаёт все роли одному администратору; контрольный список развёртывания требует перераспределения перед промышленной эксплуатацией.
Семантика принудительного исполнения и приостановки
- Приостановка блокирует эмиссию, переводы, сжигание и преобразования; она не блокирует принудительные переводы, поэтому законное распоряжение может быть исполнено во время инцидента.
- Принудительные переводы пропускают
canSend/canReceiveи проверку замороженного баланса, уменьшают замороженное количество до остатка и всё равно запускают хуки сOP_FORCED_TRANSFER. Эталонные хуки возвращаютOKдля этой операции; хук, регулирующий принудительное исполнение, может требовать ссылки на распоряжения вdata. - Заморозка может превышать баланс (ERC-7943), поэтому обременение может охватывать будущие зачисления.
Безопасность обновлений
- UUPS;
_authorizeUpgradeзащищёнUPGRADER_ROLE. - Структура хранилища ERC-7201 с пространством имён; только добавление полей.
- Проверки плагина OpenZeppelin upgrades выполняются в тестах и должны выполняться в CI перед любой транзакцией обновления.
- Параметр
optimizer.runs = 1на уровне файла удерживает реализацию в пределах EIP-170; изменение, выводящее её за этот предел, приводит к предупреждению при компиляции и к откату при развёртывании.
Безопасность зависимостей и сборки
- OpenZeppelin Contracts и Contracts-Upgradeable зафиксированы на версии 5.3.0; lock-файл закоммичен; CI использует
npm ci. - Solidity 0.8.22, viaIR, EVM
paris(без зависимости от transient storage, можно развёртывать в сетях, не принявших Cancun). - Внешние библиотеки не подключаются; delegatecall вне прокси UUPS не используется.
Состояние аудита
- 46 тестов эталонной реализации, хуков и расширений покрывают каждый из перечисленных выше инвариантов, включая рандомизированный прогон инвариантов с зафиксированным seed.
- Газ и размер измеряются скриптами из репозитория.
- Аудит
ARexToken,ARexAttestationsи эталонных хуков третьей стороной заявлен как предварительное условие для якорного участника в промышленной эксплуатации и для подачи ERC (см. Дальнейшее развитие). - Формальная верификация инвариантов конвейера включена в дорожную карту; инварианты достаточно невелики, чтобы формулироваться как свойства.
Остаточные риски, которые стандарт не устраняет
- Физическое существование и качество лота аттестуются, но не доказываются; токен делает утверждения приписываемыми конкретной стороне, но не истинными.
- Доступность офчейн-метаданных зависит от выбранного хранилища; хеш гарантирует целостность, но не доступность.
- Управление хуками и модулями надёжно лишь настолько, насколько надёжны контролирующие его ключи.