ERC-4337 Інтеграція (Account Abstraction)
ERC-4337 — це стандарт, який з'явився на Ethereum mainnet у березні 2023 року та принципово змінює те, як працюють гаманці. До цього кожен аккаунт у мережі — це або EOA (externally owned account), керований приватним ключем, або смарт-контракт. EOA простий, але жорстко обмежений: один підпис, один ключ, втратив — втратив все. ERC-4337 дозволяє кожному користувачу мати смарт-контракт-гаманець з довільною логікою авторизації — без змін у консенсусі Ethereum.
Суть архітектурного трюку: замість звичайних транзакцій користувачі створюють UserOperation об'єкти, які агрегуються в окремому mempool. Спеціалізовані вузли, звані bundlers, збирають UserOps та відправляють їх через контракт EntryPoint — singleton, розгорнутий по одній адресі через всі EVM-сумісні мережі. Вся логіка перевірки та виконання живе всередині Account контракту користувача.
Як улаштована UserOperation
UserOperation — це не транзакція в класичному сенсі. Це структура даних, яку користувач підписує та відправляє в alt mempool:
struct UserOperation {
address sender; // адреса смарт-контракту гаманця
uint256 nonce;
bytes initCode; // якщо гаманець ще не розгорнутий
bytes callData; // що виконати
uint256 callGasLimit;
uint256 verificationGasLimit;
uint256 preVerificationGas;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
bytes paymasterAndData; // хто платить за gas (опціонально)
bytes signature;
}
initCode — ключовий момент для UX. Користувач може отримати адресу гаманця (через CREATE2) до його розгортання та використовувати цю адресу для отримання активів. Гаманець розгортається автоматично при першій UserOperation — користувач не бачить окремого кроку "створити гаманець".
Bundler викликає EntryPoint.handleOps(), передаючи batch UserOps. EntryPoint робить два проходи: validation loop (перевіряє підписи та баланси) та execution loop (виконує callData). Розділення критично — validation ізольована, щоб bundler міг перевірити рентабельність без side effects.
Smart Contract Account: що реалізовувати
Мінімальний контракт Account повинен реалізовувати інтерфейс IAccount з одним методом:
function validateUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData);
validationData — упакований uint256, що містить: результат валідації (0 = успіх, 1 = невдача), validAfter та validUntil обмеження часу. Це дозволяє реалізувати часово обмежені session keys прямо в логіці валідації.
Реальна реалізація Account, з якою ми працюємо, зазвичай успадковується від BaseAccount (з репозиторію eth-infinitism/account-abstraction) і додає кастомну логіку:
contract MultiSigAccount is BaseAccount {
mapping(address => bool) public owners;
uint256 public threshold;
function _validateSignature(
UserOperation calldata userOp,
bytes32 userOpHash
) internal override returns (uint256 validationData) {
// decode multiple signatures from userOp.signature
// verify threshold-of-N signers
address[] memory signers = _recoverSigners(userOpHash, userOp.signature);
uint256 validCount = 0;
for (uint i = 0; i < signers.length; i++) {
if (owners[signers[i]]) validCount++;
}
return validCount >= threshold ? 0 : SIG_VALIDATION_FAILED;
}
}
Paymaster: Gas без ETH
Paymaster — це смарт-контракт, який спонсирує газ за користувача. Два основні патерни:
Verifying Paymaster — приймає off-chain підпис від backend-у та перевіряє його on-chain. Використовується для freemium моделей: dApp платить газ за користувачів. Backend підписує дозвіл, гаманець включає його в paymasterAndData.
ERC-20 Paymaster — користувач платить газ в ERC-20 токені (наприклад, USDC). Paymaster конвертує курс через Chainlink oracle, бере трохи більше ERC-20 у користувача та платить ETH газ сам. Користувачу взагалі не потрібен ETH.
function validatePaymasterUserOp(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external returns (bytes memory context, uint256 validationData) {
uint256 tokenAmount = (maxCost * tokenPrice) / 1e18 * 110 / 100; // +10% буфер
require(IERC20(token).allowance(userOp.sender, address(this)) >= tokenAmount);
return (abi.encode(userOp.sender, tokenAmount), 0);
}
Social Recovery
Одна з основних особливостей Account Abstraction — соціальне відновлення. Користувач призначає guardians (довірені адреси або хеші адрес), які можуть змінити owner через timelock:
function initiateRecovery(address newOwner) external onlyGuardian {
recoveryRequests[newOwner] = block.timestamp + RECOVERY_DELAY;
}
function finalizeRecovery(address newOwner) external {
require(block.timestamp >= recoveryRequests[newOwner], "Timelock active");
owner = newOwner;
delete recoveryRequests[newOwner];
}
RECOVERY_DELAY (зазвичай 48-72 години) дає користувачу час для скасування відновлення, якщо guardian скомпрометований.
Session Keys
Session keys — це тимчасові ключі з обмеженими правами. dApp просить підписати політику: "цей ключ може витратити до 10 USDC на день лише в контракті 0x...". Користувач підписує один раз, далі dApp підписує UserOps session key-ом — без popup кожен раз. Реалізується через модуль SessionKeyValidator або через кастомну логіку в validateUserOp.
Kernel від ZeroDev та Safe{Wallet} реалізують це через модульну архітектуру: Account — це execution layer, а validators/executors — підключувані модулі. Вибір базового SDK залежить від вимог: Kernel — максимальна гнучкість, Biconomy SDK — готова bundler+paymaster інфраструктура.
Stack та інфраструктура
Smart contracts: Solidity 0.8.x, eth-infinitism/account-abstraction v0.6 або v0.7, Foundry для тестів. Критично тестувати через simulateValidation — EntryPoint має правила доступу до storage для phase validation, порушення яких bundlers будуть відхиляти UserOps.
Bundler: Stackup, Alchemy, Pimlico — managed bundlers для production. Для власного — eth-infinitism/bundler (TypeScript) або Silius (Rust). Bundler повинен відповідати ERC-4337 mempool специфікації.
Frontend SDK: permissionless.js (viem-based), Biconomy SDK, ZeroDev SDK. permissionless.js — найбільш низький рівень, повний контроль над UserOperation construction.
| Компонент | Технологія | Примітка |
|---|---|---|
| Account контракт | Solidity + eth-infinitism | Аудит обов'язковий |
| Paymaster | Solidity + Chainlink | Для ERC-20 gas |
| Bundler | Stackup/Pimlico API | Managed для старту |
| Frontend SDK | permissionless.js + viem | Viem-based, активно розвивається |
| Session keys | ZeroDev Kernel / Biconomy | Ready реалізації |
Gas Overhead та L2
На Ethereum mainnet кожна UserOperation коштує дорожче, ніж звичайна EOA транзакція на ~42 000 gas (EntryPoint overhead). На L2 це майже непомітно: на Arbitrum/Optimism газ в рази дешевше, і Account Abstraction стає практичним для масового використання.
Для Polygon, Base, Optimism, Arbitrum — EntryPoint вже розгорнутий на стандартній адресі 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 (v0.6). Одна реалізація працює всім мережах.
Графік та обсяг робіт
Базова інтеграція (Account + Paymaster + bundler підключення, без кастомної логіки): 3-4 тиж. Включає: Account смарт-контракт з ECDSA або WebAuthn валідацією, Verifying Paymaster, інтеграція з managed bundler, frontend SDK.
Повна реалізація з social recovery, session keys, ERC-20 paymaster, кастомними модулями, аудитом: 8-12 тиж.
Аудит Account та Paymaster контрактів — окремий обов'язковий етап перед production розгортанням. Помилки в validateUserOp можуть дозволити drain гаманця.







