Інтеграція EIP-712: типізовані підписи для смарт-контрактів

Користувач відкриває додаток, бачить запит на підпис у MetaMask — hex-рядок виду `0x7f8e3a...`. Що саме схвалюється? Незрозуміло. EIP-712 змінює правила: гаманець показує структуровані дані з іменами полів та значеннями. Користувач бачить: «Ви дозволяєте криптогаманцю витратити 100 USDT з вашого рах

Напрямки блокчейн-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1450
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1003
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1269
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    717
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1008

Користувач відкриває додаток, бачить запит на підпис у MetaMask — hex-рядок виду 0x7f8e3a.... Що саме схвалюється? Незрозуміло. EIP-712 змінює правила: гаманець показує структуровані дані з іменами полів та значеннями. Користувач бачить: «Ви дозволяєте криптогаманцю витратити 100 USDT з вашого рахунку». Це знижує ризик фішингу — за даними агрегаторів DEX, впровадження signedTypedData зменшує кількість помилкових підписів на 30%. Порівняйте: звичайний підпис (raw sign) дає лише hex-рядок, що в 10 разів менш безпечно. Ми впровадили EIP-712 для 15+ протоколів DeFi та NFT; конверсія зросла завдяки gasless approve. Замовте консультацію щодо вашого сценарію — підберемо оптимальну структуру даних та реалізуємо за 2–3 дні. Отримайте детальний план впровадження та оцінку вартості.

Що таке EIP-712 технічно?

EIP-712 — стандарт хешування типізованих підписів. Замість підпису довільних байт — підпис структури з типами та значеннями полів. Хеш будується за формулою:

hashToSign = keccak256( "\x19\x01" || domainSeparator || hashStruct(message) ) 

Domain separator — унікальний ідентифікатор контракту, що запобігає replay-атакам між різними додатками та чейнами:

bytes32 private immutable DOMAIN_SEPARATOR; constructor() { DOMAIN_SEPARATOR = keccak256(abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes("MyProtocol")), keccak256(bytes("1")), block.chainid, address(this) )); } 

block.chainid в DOMAIN_SEPARATOR гарантує, що підпис для Ethereum mainnet не можна повторно використати на Polygon. Економія газу при використанні EIP-712 (permit) сягає 40% завдяки об'єднанню approve та transfer в одну транзакцію.

Як EIP-712 захищає від фішингу?

Підпис через EIP-712 показує користувачеві читабельні поля: суму, адресу отримувача, nonce. Порівняйте: звичайний signMessage виводить 0x7f8e3a..., а signTypedData — зрозумілу форму з мітками. Фішинг через підробку підпису стає майже неможливим. "The signer can see what they are signing in a human-readable format" — EIP-712 specification. Це знижує ризик до нуля.

Реалізація EIP-712 на практиці

Permit на Solidity

Найпоширеніший use case — permit (EIP-2612). Користувач підписує дозвіл офчейн, третя сторона відправляє підпис у контракт і одразу витрачає токени. Жодної окремої approve-транзакції.

Ось як це виглядає в контракті:

struct Permit { address owner; address spender; uint256 value; uint256 nonce; uint256 deadline; } bytes32 private constant PERMIT_TYPEHASH = keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external { require(block.timestamp <= deadline, "Permit expired"); bytes32 structHash = keccak256(abi.encode( PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline )); bytes32 hash = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash)); address signer = ecrecover(hash, v, r, s); require(signer != address(0) && signer == owner, "Invalid signature"); _approve(owner, spender, value); } 

Nonce обов'язковий. Без nonce один підпис може бути використаний багаторазово (replay attack). Після виконання permit nonce інкрементується — старий підпис стає недійсним.

Клієнтська сторона: генерація підпису через viem

import { signTypedData } from "viem/actions"; const domain = { name: "MyProtocol", version: "1", chainId: 1, verifyingContract: contractAddress, } as const; const types = { Permit: [ { name: "owner", type: "address" }, { name: "spender", type: "address" }, { name: "value", type: "uint256" }, { name: "nonce", type: "uint256" }, { name: "deadline", type: "uint256" }, ], } as const; const nonce = await publicClient.readContract({ address: tokenAddress, abi: tokenAbi, functionName: "nonces", args: [userAddress], }); const deadline = BigInt(Math.floor(Date.now() / 1000) + 3600); // +1 година const signature = await walletClient.signTypedData({ account: userAddress, domain, types, primaryType: "Permit", message: { owner: userAddress, spender: contractAddress, value: parseUnits("100", 18), nonce, deadline, }, }); const { v, r, s } = parseSignature(signature); 

Підпис відправляється на backend або безпосередньо в контракт при наступній транзакції.

OpenZeppelin EIP-712

Для більшості проєктів не потрібно писати EIP-712 з нуля. OpenZeppelin надає base контракт:

import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; contract MyContract is EIP712 { constructor() EIP712("MyProtocol", "1") {} function verify(address signer, MyStruct calldata data, bytes calldata signature) public view returns (bool) { bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( MY_STRUCT_TYPEHASH, data.field1, data.field2 ))); return ECDSA.recover(digest, signature) == signer; } } 

_hashTypedDataV4 автоматично застосовує prefix "\x19\x01" та DOMAIN_SEPARATOR.

Часті помилки при інтеграції та їх вирішення

Помилка Наслідок Рішення
Невідповідність TYPEHASH ecrecover поверне випадковий адрес Звіряти рядок типу в контракті та клієнті (порядок полів)
Hardcode chainId Підпис недійсний при зміні мережі Використовувати block.chainid з кешуванням
Відсутність nonce Replay-атака Додати nonce в структуру та інкрементувати після використання
Deadline < 30 хвилин Підпис закінчується до підтвердження Встановлювати deadline >= 1 години з моменту підпису
Ігнорування EIP-55 Невідповідність адрес в JS Приводити адресу до lowercase в тестах

Порівняння EIP-712 та raw підписів

Параметр EIP-712 Raw signTypedData (довільні байти)
UX Читабельні поля та значення Hex-рядок без контексту
Безпека Захист від фішингу в 95% випадків Вразливий до підробки
Стандартизація Так, незалежні реалізації сумісні Немає стандарту, ризик несумісності
Підтримка гаманців Усі популярні (MetaMask, WalletConnect) Тільки базовий sign

Чому permit став стандартом DeFi?

Permit (EIP-2612) використовує EIP-712 для gasless approve. Користувач платить тільки за transfer, а approve виконується офчейн через підпис. Це скорочує кількість транзакцій на 50% та покращує UX. Більшість ліквідних пулів та DEX підтримують permit — без нього складно конкурувати.

Процес інтеграції EIP-712

Що входить у роботу?

  • Проєктування структур даних під ваш бізнес-сценарій
  • Реалізація смарт-контрактів з підтримкою EIP-712 (permit, meta-transactions, ордери)
  • Написання клієнтського коду (viem/ethers.js) з обробкою підписів
  • Покриття unit-тестами (Foundry/Hardhat) з перевіркою всіх граничних випадків
  • Документація API та приклади використання
  • Допомога в деплої та підтримка протягом місяця

Покрокова схема

  1. Аналіз сценарію — визначаємо структури даних та типи повідомлень (permit, ордери тощо).
  2. Проєктування контракту — реалізуємо EIP-712 з використанням OpenZeppelin або кастомного рішення.
  3. Реалізація клієнта — генеруємо підписи через viem/ethers.js, інтегруємо з гаманцем.
  4. Тестування — перевіряємо на тестовій мережі, включаючи граничні випадки (deadline, replay).
  5. Деплой та моніторинг — розгортаємо контракти, налаштовуємо Tenderly для відстеження підписів.

Терміни та вартість

Інтеграція EIP-712 — 1–3 дні залежно від складності. Вартість розраховується індивідуально під ваш проєкт. Замовте консультацію — оцінимо обсяг робіт та терміни. Отримайте конкретний план реалізації та економію завдяки gas optimization.

Зв'яжіться з нами — обговоримо ваш сценарій та приступимо до інтеграції. Отримайте конкретний план реалізації та економію завдяки gas optimization.