Разработка ERC-4337 Account Abstraction Bundler

Bundler — центральный инфраструктурный компонент ERC-4337 экосистемы. Мы создаём production-ready bundler под ваши задачи: от базового centralized до MEV-оптимизированного с P2P mempool. Наш опыт — более 5 лет в блокчейн-разработке и более 50 внедрений ERC-4337 решений. Именно он обеспечивает работу

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

Часто задаваемые вопросы

Последние работы

  • 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

Bundler — центральный инфраструктурный компонент ERC-4337 экосистемы. Мы создаём production-ready bundler под ваши задачи: от базового centralized до MEV-оптимизированного с P2P mempool. Наш опыт — более 5 лет в блокчейн-разработке и более 50 внедрений ERC-4337 решений. Именно он обеспечивает работу Account Abstraction: принимает UserOperation от пользователей, валидирует их, группирует в batch и отправляет on-chain через EntryPoint.handleOps(). Без bundler-а Account Abstraction не работает — нет механизма доставки UserOps в блокчейн.

Разработка собственного bundler-а актуальна если: нужна кастомная мемпул логика, MEV оптимизация для UserOps, приватный bundler для конкретного приложения, или если требуется понимать и контролировать всю инфраструктуру ERC-4337. Мы гарантируем корректную реализацию storage access rules — ключевой сложности, на которой спотыкаются 70% самодельных bundler-ов.

Как Bundler проверяет UserOperation?

Пользователь создаёт UserOperation и отправляет её в bundler через JSON-RPC метод eth_sendUserOperation. Bundler выполняет серию проверок, держит UserOp в своём alt mempool, и периодически отправляет batch on-chain.

Фаза 1: Validation

Bundler вызывает EntryPoint.simulateValidation(userOp). Это view-функция (reverts с результатом через custom error), которая:

  1. Если initCode не пустой — деплоит Account контракт через factory
  2. Вызывает account.validateUserOp() — проверяет подпись, nonce
  3. Если указан Paymaster — вызывает paymaster.validatePaymasterUserOp()
  4. Возвращает ValidationResult с данными о газе, стейкинге paymaster-а, временных ограничениях
interface ValidationResult { returnInfo: { preOpGas: bigint; prefund: bigint; // сколько ETH account/paymaster депозировал в EntryPoint sigFailed: boolean; validAfter: number; validUntil: number; }; senderInfo: StakeInfo; factoryInfo?: StakeInfo; paymasterInfo?: StakeInfo; } 

prefund — ключевой момент. Account или Paymaster должны иметь депозит в EntryPoint достаточный для покрытия maxFeePerGas * (verificationGasLimit + callGasLimit). Bundler проверяет это до включения в mempool.

Почему storage access rules критичны?

ERC-4337 накладывает жёсткие ограничения на то, какой storage может читать/писать validateUserOp. Цель — предотвратить ситуацию когда одна UserOp делает другие невалидными (griefing атака).

Запрещено в validation:

  • Читать storage других контрактов, кроме самого Account и связанных entity
  • Вызывать block.timestamp, block.number (кроме ограниченного использования через validAfter/validUntil)
  • Обращаться к storage, которое может быть изменено другой UserOp в том же batch

Это требование описано в ERC-4337 specification. Bundler отслеживает storage slots, к которым обращается validation через debug_traceCall с EVM tracer. Это дорогостоящая операция — один из главных performance bottleneck-ов bundler-а.

// Упрощённо: tracer для отслеживания storage access async function traceValidation(userOp: UserOperation): Promise<StorageMap> { const trace = await provider.send('debug_traceCall', [{ to: ENTRY_POINT_ADDRESS, data: entryPoint.interface.encodeFunctionData('simulateValidation', [userOp]) }, 'latest', { tracer: bundlerCollectorTracer, // кастомный JS tracer tracerConfig: { /* ... */ } }]) return parseStorageAccess(trace) } 

bundlerCollectorTracer — JavaScript tracer для go-ethereum's debug_traceCall. Отслеживает каждый SLOAD/SSTORE opcode и связывает их с вызывающим контрактом. Это самая технически нетривиальная часть bundler-а.

Управление альтернативным Mempool

UserOp принятая в mempool должна оставаться валидной. Bundler следит за:

  • Nonce invalidation. Если on-chain нонс Account изменился (другая UserOp прошла) — pending UserOp с устаревшим nonce удаляется.
  • Deposit insufficiency. Если balance депозита в EntryPoint уменьшился (другая UserOp спонсируемая тем же Paymaster-ом прошла) — нужно пересчитать хватит ли на все pending UserOps этого Paymaster-а.
  • Gas price changes. UserOp с maxFeePerGas ниже текущего basefee — не пройдёт, bundler может временно отложить или дропнуть.
class UserOpMempool { private pool: Map<string, MempoolEntry> = new Map() async add(userOp: UserOperation): Promise<string> { const hash = getUserOpHash(userOp) // Репутационная система: ограничение по sender/paymaster/factory this.reputationManager.checkReputation(userOp) this.pool.set(hash, { userOp, prefund: await this.calculatePrefund(userOp), addedAt: Date.now() }) return hash } getBundle(maxGas: bigint): UserOperation[] { // Жадный алгоритм: выбрать UserOps с наибольшим priority fee // с учётом лимита газа и конфликтов по storage return this.selectNonConflicting( [...this.pool.values()] .sort((a, b) => Number(b.userOp.maxPriorityFeePerGas - a.userOp.maxPriorityFeePerGas)), maxGas ) } } 

Отправка Bundle on-chain

Bundler формирует batch из валидных UserOps и отправляет EntryPoint.handleOps(ops, beneficiary). beneficiary — адрес куда EntryPoint отправит собранный газ (priority fee bundler-а).

Критичный момент: bundler отправляет обычную EOA транзакцию. Он платит газ авансом, EntryPoint возмещает из депозитов Account/Paymaster. Если handleOps реверсируется — bundler теряет газ. Поэтому симуляция перед отправкой обязательна.

Защита от reverting bundle: EntryPoint в handleOps пропускает UserOps, которые реверсятся в execution phase (не в validation). Для validation фаза — если реверт, весь handleOps падает. Bundler должен убедиться что validation гарантированно пройдёт.

Децентрализация и защита: репутация и P2P

Чтобы предотвратить spam и DoS атаки, ERC-4337 вводит reputation system для unbanned entities (Paymaster, Factory, Aggregator). Логика:

class ReputationManager { // Для каждого entity отслеживаем: ops включённых vs ops неуспешных updateIncluded(entity: string): void { this.entries[entity].opsSeen++ this.entries[entity].opsIncluded++ } updateFailed(entity: string): void { this.entries[entity].opsIncluded-- // если bundle был reverted } getStatus(entity: string): 'ok' | 'throttled' | 'banned' { const entry = this.entries[entity] if (!entry) return 'ok' const ratio = entry.opsIncluded / Math.max(1, entry.opsSeen) if (ratio < MIN_INCLUSION_RATE_DENOMINATOR) return 'banned' if (entry.opsSeen > THROTTLE_THRESHOLD) return 'throttled' return 'ok' } } 

Staking в EntryPoint повышает лимиты: entity со стейком может иметь больше UserOps в mempool. Это anti-spam механизм: нельзя бесплатно флудить mempool.

Для децентрализованного bundler-а нужен P2P alt mempool — сеть для обмена UserOps между bundler нодами. ERC-4337 специфицирует протокол на базе libp2p с gossipsub:

  • Topic: user_ops/{chainId}/{entryPointAddress}
  • Message: RLP-encoded UserOperation
  • Validation: каждый узел независимо валидирует перед relay
import { createLibp2p } from 'libp2p' import { gossipsub } from '@chainsafe/libp2p-gossipsub' const libp2p = await createLibp2p({ /* ... transport, identify, etc */ services: { pubsub: gossipsub({ allowPublishToZeroPeers: true, msgIdFn: (msg) => computeUserOpHash(msg.data) }) } }) libp2p.services.pubsub.subscribe(userOpsTopic) libp2p.services.pubsub.addEventListener('message', async (event) => { const userOp = decodeUserOp(event.detail.data) await mempool.add(userOp) // со всеми проверками }) 

MEV и Bundle строительство

Bundler имеет уникальную позицию: он выбирает порядок UserOps в bundle, что открывает MEV возможности. Две стратегии:

Честный FIFO bundler — включает UserOps в порядке получения, максимизирует priority fee. Простая реализация, хорошо для permissioned bundler конкретного приложения.

MEV-aware bundler — анализирует callData UserOps, находит арбитражные возможности, строит bundle оптимально. Интеграция с flashbots MEV-boost для отправки bundle через private mempool. Экономия газовых затрат на 15-25% при MEV-оптимизации.

Стратегия Преимущества Недостатки
FIFO Простота, предсказуемость Не улавливает MEV
MEV-aware Дополнительный доход Сложнее, требует анализа callData

Что входит в работу

  1. Документация — описание архитектуры, storage access rules, схема взаимодействия.
  2. Доступы — к репозиторию, GitHub Actions, мониторингу.
  3. Обучение — воркшоп по эксплуатации и настройке bundler-а.
  4. Поддержка — 2 месяца после запуска, включая исправление критических ошибок.
  5. Исходный код — под лицензией, с инструкцией по деплою.

Готовые реализации для форка

  • Infinitism/bundler (TypeScript) — reference implementation от создателей ERC-4337
  • Stackup bundler (Go) — production bundler от Stackup
  • Silius (Rust) — high-performance bundler
  • Rundler (Rust) — bundler от Alchemy

Для кастомной разработки: TypeScript reference проще для понимания, Rust/Go лучше для production throughput.

Технологический стек и сроки

Компонент Технология
RPC сервер Node.js / Go / Rust
EVM tracing debug_traceCall + кастомный JS tracer
Mempool storage Redis / in-memory + persistence
P2P (опционально) libp2p + gossipsub
Мониторинг Prometheus + Grafana
Тестирование Foundry + Hardhat (local EntryPoint)

Базовый centralized bundler с RPC, validation, mempool и bundle submission: 6-8 недель. Основная сложность — корректный EVM tracer для storage access rules.

Production bundler с репутационной системой, P2P mempool, MEV оптимизацией, мониторингом: 3-4 месяца.

Главное предупреждение: некорректная реализация storage access rules ведёт к либо принятию опасных UserOps (DoS риск), либо к отклонению валидных (плохой UX). Тщательное тестирование на всех edge cases обязательно.

Закажите разработку custom bundler — мы реализуем его под вашу инфраструктуру. Свяжитесь с нами для консультации: поможем выбрать стратегию и рассчитать стоимость под вашу задачу.