Розроблення системи session keys для gasless UX
Стандартний UX Web3 застосунку: кожне дійво користувача — окремна підпис в MetaMask. Граєш у гру — підписуєш кожен хід. Торгуєш на DEX — підписуєш кожен swap. Це неприйнятно для масового продукту. Session keys розв'язують проблему: користувач підписує одну транзакцію (відкриття сесії), далі застосунок діє від його імені в рамках заданих обмежень, без постійних підтверджень.
Це можливо тільки з Account Abstraction (ERC-4337) — тому що у Smart Account може бути кілька авторизованих підписантів з різними правами, на відміну від EOA де є тільки один приватний ключ.
Як працюють session keys
Архітектура: validator плагін у Smart Account. Account перевіряє підпис через validator — основний ECDSA validator вимагає ключ користувача. Session key validator вимагає тільки ключ сесії, але перевіряє обмеження:
Основний ключ користувача:
→ Validator: ECDSAValidator(userKey)
→ Може всe
Session key:
→ Validator: SessionKeyValidator
→ Перевіряє: правильний підписант + обмеження дотримані
Реалізації session key validator:
Kernel (ZeroDev) — найбільш використовується. Session key validator зі вбудованими permission модулями: обмеження по контрактах, функціях, параметрах, лімітах витрат.
Biconomy Smart Account — власний Session Key Manager модуль.
Safe + safe-modules — Session Keys через Safe Plugin.
Реалізація на ZeroDev Kernel
import {
createKernelAccount,
createKernelAccountClient,
createZeroDevPaymasterClient,
} from '@zerodev/sdk';
import {
signerToSessionKeyValidator,
ParamOperator,
oneAddress,
} from '@zerodev/session-key';
import { signerToEcdsaValidator } from '@zerodev/ecdsa-validator';
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
import { parseAbi, encodeFunctionData } from 'viem';
// 1. Створюємо тимчасовий session key (ephemeral keypair)
const sessionPrivateKey = generatePrivateKey();
const sessionKeySigner = privateKeyToAccount(sessionPrivateKey);
// 2. Визначаємо permissions для сесії
const sessionKeyValidator = await signerToSessionKeyValidator(publicClient, {
signer: sessionKeySigner,
validatorData: {
validUntil: Math.floor(Date.now() / 1000) + 86400, // 24 години
validAfter: 0,
paymaster: oneAddress, // дозволити будь-якого paymaster
permissions: [
{
target: GAME_CONTRACT_ADDRESS,
valueLimit: BigInt(0), // не можна відправляти ETH
abi: parseAbi(['function makeMove(uint8 x, uint8 y) external']),
functionName: 'makeMove',
args: [
{ operator: ParamOperator.LESS_THAN, value: 8n }, // x < 8
{ operator: ParamOperator.LESS_THAN, value: 8n }, // y < 8
],
},
],
},
});
// 3. Створюємо account зі session key validator
const account = await createKernelAccount(publicClient, {
plugins: {
sudo: await signerToEcdsaValidator(publicClient, { signer: userSigner }),
regular: sessionKeyValidator,
},
kernelVersion: KERNEL_V3_1,
});
// 4. Зберігаємо session key (у IndexedDB або пам'яті)
const serializedSessionKey = await sessionKeyValidator.serializeSessionKey();
// → передаємо backend або зберігаємо локально
Після створення сесії — backend (або сам браузер) може підписувати транзакції session key без взаємодії з користувачем:
// Використання збереженої сесії (наприклад, на сервері)
const restoredValidator = await deserializeSessionKeyValidator(
publicClient,
{ serializedSessionKey },
);
const kernelClient = createKernelAccountClient({
account,
chain: arbitrum,
bundlerTransport: http(BUNDLER_RPC),
paymaster: createZeroDevPaymasterClient({ ... }),
});
// Транзакція без підпису користувача
const txHash = await kernelClient.sendTransaction({
to: GAME_CONTRACT_ADDRESS,
data: encodeFunctionData({
abi: parseAbi(['function makeMove(uint8 x, uint8 y) external']),
functionName: 'makeMove',
args: [3n, 4n],
}),
});
// Газ оплачує Paymaster, користувач не підписує
Gasless: Paymaster інтеграція
Session keys прибирають необхідність підтверджувати кожну операцію. Paymaster прибирає необхідність тримати нативний токен для газу. Разом — повністю gasless UX.
ERC-4337 Paymaster: смарт-контракт який спонсирує газ для UserOperations. Два типи:
Verifying Paymaster: перед кожною UserOp викликає ваш backend для перевірки. Backend підписує дозвіл. Гнучко: ви контролюєте які операції спонсирувати.
ERC-20 Paymaster: приймає оплату в ERC-20 токенах (USDC) замість ETH. Користувач платить газ у USDC, paymaster конвертує та платить у ETH.
// Verifying Paymaster backend логіка
export async function signPaymasterRequest(
userOp: UserOperation,
): Promise<{ paymasterData: Hex; paymasterValidationGasLimit: bigint }> {
// Перевіряємо: можемо лі спонсирувати цю операцію?
const user = await getUserBySmartAccount(userOp.sender);
// Обмеження: не більше 100 спонсорованих операцій на день
const dailyCount = await getDailySponsoredCount(user.id);
if (dailyCount >= 100) throw new Error('Daily limit exceeded');
// Обмеження: тільки whitelisted контракти
const callData = decodeCallData(userOp.callData);
if (!isWhitelisted(callData.to)) throw new Error('Contract not whitelisted');
// Підписуємо дозвіл
const validUntil = Math.floor(Date.now() / 1000) + 300; // 5 хвилин
const signature = await paymasterSigner.signTypedData({
domain: PAYMASTER_DOMAIN,
types: PAYMASTER_TYPES,
message: { userOp, validUntil },
});
return {
paymasterData: encodeAbiParameters(
[{ type: 'uint48' }, { type: 'bytes' }],
[validUntil, signature],
),
paymasterValidationGasLimit: 100_000n,
};
}
Вартість спонсирування: на Arbitrum One — $0.001–$0.005 за спонсоровану UserOp. На Ethereum mainnet — $0.50–$2.00. Для ігрових застосунків — L2 обов'язковий.
Paymaster-as-a-Service провайдери: Pimlico (Alto bundler + paymaster), ZeroDev, Biconomy. Pimlico Verifying Paymaster + Alto bundler — найбільш використовується комбінація в production.
Обмеження та безпека session keys
Що потрібно обмежувати
Session key validator повинен примушувати обмеження:
- Контракти: тільки вказані адреси. Не можна вызивати довільні контракти session key-ом.
-
Функції: тільки конкретні функції. Session key для гри не повинен мочи вызивати
transferу ERC-20. - Параметри: діапазони значень (x < 8, amount <= maxAmount).
- Value лімітом: максимальний ETH який можна відправити. Для більшості ігор — 0.
- Spending лімітом: загальний ліміт потрачених ERC-20 токенів за час сесії.
- Expiry: час життя сесії. Для гри — 1–8 годин. Для trading бота — до 24 годин.
Зберігання session key
Session key — приватний ключ з обмеженими правами. Але його компрометація все одно небезпечна в рамках permissions.
Браузер: sessionStorage (живе до закриття таба) або indexedDB з шифруванням. Не використовуйте localStorage (доступна між сеансами, XSS ризик).
Backend: якщо сесія управляється сервером (для server-side автоматизації) — зберігаємо в зашифрованому вигляді (KMS), привʼязуємо до user session token.
// Безпечне зберігання session key у браузері (зашифрований user-derived key)
async function storeSessionKey(
sessionPrivateKey: Hex,
serializedPermissions: string,
userAuthKey: CryptoKey,
): Promise<void> {
const iv = crypto.getRandomValues(new Uint8Array(12));
const data = new TextEncoder().encode(
JSON.stringify({ sessionPrivateKey, serializedPermissions }),
);
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
userAuthKey,
data,
);
sessionStorage.setItem('session_key', JSON.stringify({
iv: Array.from(iv),
data: Array.from(new Uint8Array(encrypted)),
}));
}
Практичний приклад: GameFi сесія
Типовий флоу для Play-to-Earn гри:
1. Користувач натискає "Почати гру"
2. Один approve у кошельку: відкриваємо сесію на 4 години
Permissions: вызов makeMove(x,y), claimReward(), тільки GameContract
3. Користувач грає — кожен хід підписується session key автоматично
4. Ходи відправляються через bundler, газ оплачує Paymaster
5. Через 4 години сесія істікає — потрібен новий approve
Результат: користувач бачить ігровий інтерфейс без постійних вспливаючих вікон MetaMask. Onboarding близький до Web2.
Інструментарій
Ядро: @zerodev/sdk + @zerodev/session-key — найбільш зрілий. Підтримка: Arbitrum, Optimism, Base, Polygon, Ethereum mainnet. Альтернатива: Biconomy SDK v4 з сесійними модулями. Bundler: Alto (Pimlico), Stackup (Alchemy), Etherspot. Мониторинг UserOps: Jiffyscan, Pimlico dashboard.
| Задача | Інструмент |
|---|---|
| Session key validator | ZeroDev Kernel / Biconomy |
| Paymaster | Pimlico / ZeroDev |
| Bundler | Alto (Pimlico) |
| AA гаманець | Kernel v3 / Safe |
| Frontend | wagmi v2 + @zerodev/wagmi |
Ориєнтири по строкам
Базова реалізація (session keys + verifying paymaster, один ланцюг): 3–4 тижні. Повна система з multi-chain підтримкою, кастомними permission модулями, ERC-20 paymaster та аналітикою спонсорованих операцій: 6–8 тижнів.







