ERC-1271: подпись смарт-аккаунта при входе на сайт
Оглавление курса «Web3: вход, смарт-аккаунты и индексатор» · Урок 6 из 30.
Не каждый адрес Ethereum принадлежит обычному аккаунту с одним ключом. Контрактный аккаунт может требовать несколько подписей, использовать роли или собственный порядок согласования. ERC-1271 задаёт интерфейс проверки подписи таким контрактом. В этом уроке добавим эту границу в серверный вход библиотеки. Результат — сайт не отвергает все смарт-аккаунты и не принимает их по неподходящему EOA-правилу.
Предполагается общий маршрут SIWE, одноразовый challenge и явная сеть31337. Программы, узлы, контракты и подписи не запускались. Локальный пример служит для объяснения механизма; production-адрес кошелька или мультиподписи здесь не выдумывается.
Кто подтверждает подпись
Для EOA проверяется криптографическая связь сообщения с адресом. Для контрактного аккаунта право определяется его кодом и текущим состоянием. Стандартный метод isValidSignature получает хеш и подпись и возвращает специальное значение, если проверка успешна. Это не обязательное восстановление одного владельца: контракт может иметь более сложную модель.
Успешный ответ обозначается значением 0x1626ba7e для стандартного интерфейса bytes32,bytes. Другой ответ не принимается как истина по правилу «любая ненулевая строка». Если вызов откатился или endpoint недоступен, результат не считается положительным. Совместимый адаптер должен точно соблюдать формат выбранного интерфейса.
Проверка происходит в сети, указанной сообщением. Один и тот же адрес в другой цепочке может содержать другой контракт или не содержать кода. Нельзя выбрать произвольный RPC, на котором ответ выглядит удобнее. Сервер использует разрешённый клиент сети challenge и сохраняет происхождение проверки.
Учебный контракт одного подписанта
Чтобы увидеть интерфейс, приведём отдельный демонстрационный контракт. Он не изменяет CourseCatalog и не является полным смарт-кошельком: не умеет выполнять пользовательские операции, хранить средства с политикой доступа или управлять владельцами. Используем библиотечную ECDSA из OpenZeppelinContracts5.x как явную зависимость будущего упражнения.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
contract TeachingSignatureAccount {
address public immutable signer;
constructor(address signer_) {
require(signer_ != address(0), "zero signer");
signer = signer_;
}
function isValidSignature(bytes32 hash, bytes calldata signature)
external view returns (bytes4)
{
(address recovered, ECDSA.RecoverError error,) =
ECDSA.tryRecover(hash, signature);
if (error == ECDSA.RecoverError.NoError && recovered == signer) {
return 0x1626ba7e;
}
return 0xffffffff;
}
}
Это полный исходник маленького адаптера подписи, но не готовая зависимость проекта: версия библиотеки при отдельной установке фиксируется и её API сверяется. Установка и компиляция здесь не проводились. Мы не заявляем, что этот контракт уже создан в лаборатории или что его address известен.
Хеш, переданный в isValidSignature, должен соответствовать правилам подписанного сообщения. Нельзя взять случайный SHA256 строки вместо Ethereum-назначения подписи и ожидать совместимости. Для SIWE используем библиотечный маршрут проверки, который согласует формат и алгоритм. Контракт в листинге лишь показывает стандартную точку решения.
Проверка на сервере
Общий verifySiweMessage через Public Client способен работать с контрактным контекстом. Сервер не ограничивается функцией восстановления EOA-адреса, если политика сайта поддерживает ERC-1271. Прямой ручной вызов стандарта допустим в отдельном адаптере, но тогда разработчик явно отвечает за хеширование, сеть, ABI и точное возвращаемое значение.
Определение типа аккаунта по наличию кода также имеет современные нюансы, включая делегированное исполнение и другие расширения Ethereum. Не следует строить вечное правило «нет кода значит только EOA» без указания профиля сети и поддерживаемых механизмов. В этом курсе сначала рассматриваем классический EOA и уже развёрнутый ERC-1271-контракт; дополнительные форматы вводятся отдельно.
Неразвёрнутый адрес будущего смарт-аккаунта — ещё один случай. Для него обычный вызов ERC-1271 невозможен без дополнительного механизма. Сервер не принимает предполагаемый будущий код на основании обещания клиента. Если сайт поддерживает counterfactual signatures, он явно выбирает соответствующий стандарт и исследует его условия. Наш текущий маршрут не заявляет такую поддержку автоматически.
Валидность может измениться
Контракт может сменить владельца или порог подписей. Тогда одна и та же подпись для одного хеша способна получить другой результат позже. ERC-1271 не требует, чтобы решение было вечной чистой математической функцией без состояния. Поэтому серверная сессия для контрактного аккаунта нуждается в политике продолжения и отзыва.
SIWE рекомендует учитывать такие изменения. Можно ограничить срок сессии и повторять проверку важных действий или получать уведомления о соответствующих изменениях, если они доступны. Конкретная схема зависит от кошелька. Нельзя обещать автоматический отзыв любой сессии по любому изменению контракта, если приложение не знает механизмов этого аккаунта.
Базовый реестр курса имеет неизменяемого издателя, но адрес издателя сам может быть контрактом. Это отдельная возможность управления подписью. Наш учебный TeachingSignatureAccount не выполняет publish, поэтому не следует назначать его полноценным издателем и ждать, что он сможет отправлять вызовы. Проверка подписи и исполнение операции являются разными интерфейсами.
Ожидаемые случаи
Для корректного подписанта адаптер возвращает magic value. Для другого адреса или неправильной формы подписи возвращается отказ. При другой сети сервер не выбирает случайный контракт. При смене правил аккаунта новая проверка может отличаться от старой. Эти результаты описаны как ожидаемые, без запуска контрактного примера.
Для упражнения объясните, почему владельца контракта нельзя просто подставить как адрес сессии. Пользователь входит контрактным адресом, а его внутренние правила лишь подтверждают подпись. Ресурсы сессии привязаны к проверенному адресу аккаунта, а не к случайно найденному владельцу. Итог — сервер поддерживает разные модели аккаунта, сохраняя точное назначение проверки. Стандарт приведён в ERC-1271, криптографические утилиты — в OpenZeppelin5.x.
Версия библиотеки и интерфейс
OpenZeppelin5.x в листинге обозначает семейство документации, а конкретный проект при разрешённой установке фиксирует точный релиз и его lockfile. Декларация импорта не доказывает наличие зависимости в рабочей папке. Этот шаг в нашей подготовке не выполнялся, поэтому пример не объявляется скомпилированным.
При использовании другого проверяющего контракта сохраняется его адрес, сеть и интерфейс. Нельзя заменить код адреса своим локальным адаптером только потому, что оба возвращают magic value. Важны полномочия настоящего аккаунта, а не успешный ответ произвольного учебного контракта. Серверное происхождение проверки всегда связано с сообщением и разрешённой конфигурацией.
Что хранить после проверки
Рядом с результатом полезно сохранить сеть, адрес аккаунта и момент проверки. Один ответ ERC-1271 не даёт бессрочного подтверждения на всех сетях. Если политика кабинета требует повторной оценки при чувствительном действии, это отдельное решение сервера с собственным источником состояния.