Разработка системы session keys для gasless UX

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы session keys для gasless UX
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1058
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка системы session keys для gasless UX

Стандартный UX Web3 приложения: каждое действие пользователя — отдельная подпись в MetaMask. Играешь в игру — подписываешь каждый ход. Торгуешь на DEX — подписываешь каждый swap. Это неприемлемо для массового продукта. Session keys решают проблему: пользователь подписывает одну транзакцию (открытие сессии), дальше приложение действует от его имени в рамках заданных ограничений, без постоянных подтверждений.

Это возможно только с Account Abstraction (ERC-4337) — потому что у Smart Account может быть несколько авторизованных подписантов с разными правами, в отличие от EOA где есть только один приватный ключ.

Как работают session keys

Архитектура: validator plugin в Smart Account. Account проверяет подпись через validator — основной ECDSA validator требует ключ пользователя. Session key validator требует только ключ сессии, но проверяет ограничения:

Основной ключ пользователя:
  → Validator: ECDSAValidator(userKey)
  → Может всё

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],
  }),
});
// Gas оплачивает Paymaster, пользователь не подписывает

Gasless: Paymaster интеграция

Session keys убирают необходимость подтверждать каждую операцию. Paymaster убирает необходимость держать нативный токен для gas. Вместе — полностью gasless UX.

ERC-4337 Paymaster: смарт-контракт, который спонсирует gas для UserOperations. Два типа:

Verifying Paymaster: перед каждой UserOp вызывает ваш backend для проверки. Backend подписывает разрешение. Гибко: можно контролировать какие операции спонсировать.

ERC-20 Paymaster: принимает оплату в ERC-20 токенах (USDC) вместо ETH. Пользователь платит gas в USDC, paymaster конвертирует и платит в ETH.

// Verifying Paymaster backend logic
export async function signPaymasterRequest(
  userOp: UserOperation,
): Promise<{ paymasterData: Hex; paymasterValidationGasLimit: bigint }> {
  // Проверяем: можем ли спонсировать эту операцию?
  const user = await getUserBySmartAccount(userOp.sender);
  
  // Ограничение: не более 100 sponsored операций в день
  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 за sponsored UserOp. На Ethereum mainnet — $0.50–$2.00. Для игровых приложений — L2 обязателен.

Провайдеры Paymaster-as-a-Service: Pimlico (Alto bundler + paymaster), ZeroDev, Biconomy. Пиmlico Verifying Paymaster + Alto bundler — наиболее используемая комбинация в production.

Ограничения и безопасность session keys

Что нужно ограничивать

Session key validator должен принудительно ограничивать:

  • Контракты: только указанные адреса. Нельзя вызывать произвольные контракты session key-ом.
  • Функции: только конкретные функции. Session key для игры не должен мочь вызвать transfer в ERC-20.
  • Параметры: диапазоны значений (x < 8, amount <= maxAmount).
  • Value limit: максимальный ETH который можно отправить. Для большинства игр — 0.
  • Spending limit: общий лимит потраченных 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 сессия

Типичный flow для Play-to-Earn игры:

1. Пользователь нажимает "Начать игру"
2. Один approve в кошельке: открываем сессию на 4 часа
   Permissions: вызов makeMove(x,y), claimReward(), только GameContract
3. Пользователь играет — каждый ход подписывается session key автоматически
4. Ходы отправляются через bundler, gas оплачивает 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 wallet Kernel v3 / Safe
Frontend wagmi v2 + @zerodev/wagmi

Ориентиры по срокам

Базовая реализация (session keys + verifying paymaster, один chain): 3–4 недели. Полная система с multi-chain поддержкой, custom permission модулями, ERC-20 paymaster и аналитикой спонсированных операций: 6–8 недель.