Безопасность

Как найти и удалить активную EIP-7702 делегацию аккаунта

Как проверить код EOA через eth_getCode, распознать делегацию EIP-7702, выяснить адрес реализации, безопасно очистить её и проверить результат.

Как найти и удалить активную EIP-7702 делегацию аккаунта

Короткий ответ: активную EIP-7702 делегацию надёжнее всего искать через RPC-вызов eth_getCode для своего адреса в каждой используемой EVM-сети. Если ответ начинается с 0xef0100 и после префикса содержит 20-байтовый адрес, EOA делегирован коду по этому адресу. Для очистки нужна новая подписанная authorization tuple, направленная на нулевой адрес, и совместимая EIP-7702 транзакция. После подтверждения eth_getCode должен вернуть 0x.

Удаление делегации не отзывает ERC-20 approvals, NFT approvals, сессии dapp и подписи permit. Это отдельное изменение поля code у аккаунта. Если приватный ключ уже скомпрометирован, очистка не делает ключ безопасным: злоумышленник способен создать новую делегацию или обычную транзакцию с последующим nonce.

Что именно хранит EIP-7702

Обычный EOA исторически имеет баланс, nonce и пустой code. EIP-7702 позволяет владельцу подписать authorization, после обработки которой code аккаунта становится специальным указателем. Байты выглядят как 0xef0100 плюс адрес контракта-делегата. Полная механика разобрана в статье о том, как EIP-7702 добавляет код обычному адресу.

Указатель не копирует весь байткод в EOA. Когда кто-то вызывает делегированный аккаунт, EVM берёт код с указанного адреса, но исполняет его в контексте аккаунта пользователя. Баланс и storage принадлежат EOA. Поэтому опасность зависит не только от наличия делегации, но и от логики реализации, её возможности обновления, инициализированного storage и прав подписанта.

Делегация постоянна. Она не исчезает после одной транзакции, перезапуска кошелька или отключения сайта. Очистить её можно новой authorization tuple. Спецификация задаёт нулевой адрес 0x0000000000000000000000000000000000000000 как команду вернуть code hash аккаунта к пустому значению.

Подготовка перед проверкой

  1. Запишите публичный адрес аккаунта. Приватный ключ и seed-фраза для чтения code не нужны.
  2. Составьте список сетей, где адрес использовался. Ethereum, Base, Arbitrum и другие EVM-сети хранят состояние независимо.
  3. Выберите доверенный RPC для каждой сети. Лучше сравнить результат двух независимых endpoints, если первый ответ вызывает сомнение.
  4. Не подключайте кошелёк к случайному «scanner» только ради чтения. Публичный адрес можно проверить без подписи и подключения.
  5. Если есть признаки компрометации, сначала подготовьте чистый адрес и план переноса активов. Не раскрывайте резервную фразу предполагаемому сервису поддержки.

Один и тот же шестнадцатеричный адрес может быть делегирован в одной сети и оставаться обычным EOA в другой. Проверка только Ethereum mainnet не говорит о состоянии L2. Даже authorization с универсальным chain ID не объединяет состояния сетей: каждая цепочка применяет изменение отдельно.

Способ 1: проверить адрес через eth_getCode

Стандартный JSON-RPC метод eth_getCode принимает адрес и номер блока. Для текущего подтверждённого состояния используется тег latest. Запрос выглядит так:

{
  "jsonrpc": "2.0",
  "method": "eth_getCode",
  "params": [
    "0xВАШ_ПУБЛИЧНЫЙ_АДРЕС",
    "latest"
  ],
  "id": 1
}

Вместо шаблона подставляется только публичный адрес. Отправлять такой запрос можно через локальный RPC-клиент, консоль разработчика доверенного узла или собственный скрипт. Не вставляйте приватный ключ, подпись или seed-фразу.

Возможны три основных результата:

  • 0x – code пуст в этой сети на указанном блоке, активной EIP-7702 делегации нет.
  • 0xef0100… и ещё 20 байтов – найден delegation indicator. Последние 40 hex-символов задают адрес делегата.
  • Другой непустой bytecode – это не стандартный EIP-7702 указатель. Возможно, проверяется адрес обычного контракта, а не EOA, либо сеть использует другую механику.

Стандартный indicator имеет 23 байта: три байта префикса и 20 байтов адреса. В hex-ответе это 0x, затем шесть символов ef0100 и 40 символов адреса. Не определяйте делегацию только по тому, что обозреватель помечает аккаунт как contract. Проверяйте сами байты.

Как извлечь адрес делегата

Допустим, RPC вернул значение вида 0xef0100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa. Префикс 0xef0100 отбрасывается, а оставшиеся 40 hex-символов превращаются в адрес 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa. Именно байткод по этому адресу будет использоваться при вызове аккаунта.

Дальше проверьте code делегата отдельным eth_getCode. Пустой code означает, что указатель ведёт в адрес без исполняемого кода. Это может сделать вызовы фактически пустыми, но не очищает indicator у EOA. Если делегат сам указывает на другую EIP-7702 делегацию, EVM следует только за первым указателем и не строит бесконечную цепочку.

Не ограничивайтесь именем реализации. Важны точный адрес, сеть, bytecode, способ инициализации и возможность обновления. Контракт с известным названием может иметь другой код по похожему адресу. Поддельный интерфейс способен предложить делегацию к вредоносной копии.

Способ 2: проверить обозреватель блоков

Некоторые обозреватели отдельно показывают, что EOA делегирован коду, и выводят адрес реализации. Это удобно как вторичная проверка, но внешний вид и названия полей меняются. Универсальный признак остаётся тем же: результат eth_getCode с префиксом 0xef0100.

В истории аккаунта найдите транзакцию типа EIP-7702 и authorization list. Сопоставьте authority, chain ID, адрес делегата и nonce. Sender транзакции не обязан совпадать с authority: спонсор или relayer может оплатить gas, а владелец EOA подписывает только authorization.

История полезна для расследования, но текущее состояние важнее. После первой делегации могла быть вторая authorization, которая заменила адрес, или очистка на нулевой адрес. Последняя видимая транзакция тоже может находиться в неподтверждённом или реорганизованном блоке. Поэтому итог всегда перепроверяется через RPC на подтверждённом блоке.

Как безопасно удалить делегацию

Для очистки владелец authority подписывает новую authorization tuple с адресом 0x0000000000000000000000000000000000000000. В tuple входят chain ID, нулевой адрес, текущий nonce authority и подпись. Затем совместимый отправитель включает её в authorization list EIP-7702 транзакции и оплачивает gas.

  1. Переключитесь на конкретную сеть, где eth_getCode показал indicator.
  2. Получите текущий подтверждённый nonce аккаунта. Обычная pending-транзакция способна изменить ожидаемое значение.
  3. В совместимом кошельке или проверенном инструменте выберите именно удаление делегации, а не замену на новый implementation.
  4. Перед подписью проверьте authority, chain ID, nonce и нулевой адрес назначения authorization.
  5. Проверьте обычную транзакцию-носитель: сеть, sender, получатель, value и calldata. Для очистки не должно требоваться переводить активы неизвестному адресу.
  6. Отправьте транзакцию и дождитесь включения в блок.
  7. Повторите eth_getCode для authority. Правильный результат после очистки – 0x.

Если используемый кошелёк не поддерживает создание clear authorization, не подписывайте найденную в чате сырую структуру вслепую. Ошибка в chain ID, nonce или адресе может не примениться, а вредоносная tuple установит другой делегат. Безопаснее использовать реализацию, которая явно показывает поля authorization и прошла независимую проверку.

Почему статус транзакции недостаточен

EIP-7702 обрабатывает authorization list до основной фазы выполнения транзакции. Спецификация отдельно указывает, что изменения delegation indicator не откатываются, если последующий вызов завершился ошибкой. Поэтому receipt со статусом failed не доказывает, что очистка не произошла.

Верно и обратное: успешный receipt не гарантирует, что конкретная tuple была принята. Неверная подпись, nonce или chain ID заставляют клиент пропустить tuple и продолжить обработку. Единственная надёжная финальная проверка – повторный eth_getCode для authority после подтверждения блока.

Если результат всё ещё начинается с 0xef0100, сравните адрес делегата и nonce до и после операции. Не повторяйте ту же подпись автоматически. Повторно использованный nonce станет недействительным, а параллельная транзакция могла опередить очистку. Основы счётчика разобраны в материале о nonce в Ethereum.

Что очистка не удаляет

EIP-7702 code и разрешения токенов хранятся в разных местах. ERC-20 allowance находится в storage контракта токена, NFT operator approval – в контракте коллекции, а WalletConnect session – в кошельке и приложении. После очистки отдельно проверьте и при необходимости отзовите approvals.

Storage EOA, созданный во время делегированного исполнения, также не обязан очищаться вместе с code. Нулевая authorization возвращает пустой code hash, но данные аккаунта могут сохраниться. Если позже установить совместимый или вредоносный делегат, он потенциально прочитает прежние storage slots. Полное понимание зависит от конкретной реализации.

Очистка не отменяет ранее подписанные сообщения. Permit или другая offchain-подпись может оставаться действительной до deadline или использования nonce. Перед подтверждением полезно понимать, чем подпись сообщения отличается от транзакции.

Если ключ мог попасть к злоумышленнику

Владелец скомпрометированного приватного ключа и злоумышленник обладают одинаковой криптографической властью над EOA. После очистки атакующий может подписать новую authorization с актуальным nonce. EIP-7702 не превращает старый ключ в отозванный и не создаёт встроенный второй фактор.

  1. На чистом устройстве создайте новый кошелёк с новой резервной фразой.
  2. Проверьте текущий code, балансы, nonce, approvals и pending-транзакции старого адреса.
  3. Если реализация делегата позволяет безопасный пакетный вывод, сначала убедитесь в точном коде и правах. Не полагайтесь на название.
  4. Перенесите нативную монету и токены на новый адрес с учётом gas и конкуренции за nonce.
  5. Очистите делегацию и approvals, если это ещё имеет смысл, но считайте старый адрес небезопасным.

Подробный порядок при утечке ключа описан в инструкции что делать после компрометации кошелька. Не импортируйте старую seed-фразу в новый профиль и не проверяйте её на сайте.

Типичные ошибки

  • Проверка одной сети. Code, nonce и делегация существуют отдельно в каждой EVM-цепочке.
  • Отключение dapp вместо очистки. Разрыв сессии не меняет account code.
  • Отзыв approvals вместо очистки. Allowance и delegation indicator не заменяют друг друга.
  • Доверие карточке обозревателя. Интерфейс может запаздывать или неверно классифицировать адрес.
  • Неправильный nonce. Authority nonce проверяется при обработке tuple и затем увеличивается.
  • Слепая подпись универсального chain ID. Значение 0 допускается стандартом, но расширяет область действия подписи и требует особой осторожности.
  • Ожидание отката при failed receipt. Обработка authorization не откатывается вместе с основной фазой выполнения.
  • Возврат к скомпрометированному ключу. Пустой code не устраняет знание приватного ключа атакующим.

Контрольный список после удаления

  • eth_getCode возвращает 0x в нужной сети.
  • Проверены все другие EVM-сети, где использовался тот же адрес.
  • Nonce соответствует последним подтверждённым и pending-транзакциям.
  • ERC-20 и NFT approvals проверены отдельно.
  • WalletConnect и другие активные сессии закрыты при необходимости.
  • Неиспользованные offchain-подписи учтены по nonce и deadline.
  • При компрометации ключа активы перенесены на новый адрес.

Итог

EIP-7702 делегация обнаруживается не по значку кошелька, а по 23-байтовому code: 0xef0100 и адресу реализации. Очистка выполняется новой authorization tuple на нулевой адрес. После блока нужно снова вызвать eth_getCode и получить 0x.

Эта операция возвращает EOA пустой code, но не очищает approvals, storage, сессии и утекший приватный ключ. Поэтому проверка делегации – один пункт полноценного аудита аккаунта, а не универсальная кнопка отмены всех разрешений.