Интеграция EIP-191 (подписи сообщений)

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Интеграция EIP-191 (подписи сообщений)
Простая
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1258
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1170
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    873
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1092
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    563
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    830

Интеграция EIP-191 (подписи сообщений)

Пользователь подключил MetaMask, вы хотите убедиться что он — владелец адреса, без отправки транзакции. Или нужно реализовать gasless whitelist: backend выдаёт подписанное разрешение, контракт верифицирует его on-chain. Оба кейса — EIP-191.

Что делает EIP-191

EIP-191 стандартизирует формат подписываемых сообщений в Ethereum. Без стандарта подпись произвольных байтов совпадает с подписью транзакции — теоретический вектор фишинга. EIP-191 добавляет префикс \x19Ethereum Signed Message:\n{length} перед хешированием, делая подписи специфичными для Ethereum и нечитаемыми как транзакции.

Версии EIP-191:

  • 0x45personal_sign (добавляет текстовый префикс, человекочитаемо в MetaMask)
  • 0x01 — structured data (это EIP-712, расширение EIP-191)
  • 0x00 — validator data (менее распространён)

Большинство кейсов — версия 0x45: personal_sign в MetaMask показывает пользователю читаемый текст, пользователь понимает что подписывает.

Верификация on-chain

В Solidity верификация через ecrecover:

function verify(string calldata message, bytes calldata signature) 
    public pure returns (address signer) 
{
    bytes32 messageHash = keccak256(bytes(message));
    bytes32 ethSignedHash = keccak256(
        abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash)
    );
    return ECDSA.recover(ethSignedHash, signature);
}

OpenZeppelin ECDSA.recover — правильный способ: обрабатывает v = 27/28, защищён от signature malleability (проверяет, что s находится в нижней половине кривой, согласно EIP-2).

Типичная ошибка: хешировать строку напрямую через keccak256(abi.encodePacked(message)) без EIP-191 префикса. Подпись с MetaMask (personal_sign) содержит префикс — верификация без него даст неверный signer.

Кейс: gasless whitelist через backend-подпись

Backend хранит whitelist адресов. Вместо хранения whitelist on-chain (дорого, требует транзакции для добавления), backend подписывает разрешение для конкретного адреса. Пользователь предъявляет подпись в контракт при mint'е:

function mint(bytes calldata signature) external {
    bytes32 hash = keccak256(abi.encodePacked(msg.sender, address(this)));
    bytes32 ethHash = MessageHashUtils.toEthSignedMessageHash(hash);
    address signer = ECDSA.recover(ethHash, signature);
    require(signer == trustedSigner, "Invalid signature");
    _mint(msg.sender, nextTokenId++);
}

Важно включить address(this) в хеш — защита от replay между контрактами. Включить block.chainid или chainId — защита от replay между сетями. Для одноразовых разрешений — nonce пользователя в хеше.

Для более структурированных данных (сумма, deadline, конкретный токен) лучше EIP-712 — пользователь видит каждое поле в MetaMask, не просто хеш.

Frontend-интеграция

С viem:

const signature = await walletClient.signMessage({ message: "Verify ownership" });

С ethers.js:

const signature = await signer.signMessage("Verify ownership");

Оба возвращают 65-байтовую подпись (r + s + v). Передаётся в контракт как bytes.

Сроки

Интеграция EIP-191 в существующий контракт (верификация подписи, protection от replay) + frontend-код — 1 рабочий день. С backend-сервисом для выдачи подписей — 2-3 дня.