Три точки, где теряется UserOperation
- Ошибка eth_sendUserOperation означает, что bundler не принял объект в свой mempool; AA-префикс помогает найти слой отказа, но точный текст зависит от версии EntryPoint.
- Возвращённый userOpHash подтверждает принятие после simulation этим bundler, а не включение в блок и не успех целевого действия.
- После включения проверяют отдельный UserOperation receipt и поле success; receipt внешнего handleOps может охватывать несколько операций.
| Идентификатор | Где появляется | Что доказывает |
|---|---|---|
| userOpHash | Ответ bundler после принятия объекта | Конкретные поля UserOperation, EntryPoint и chain domain; не inclusion |
| transactionHash | После включения bundle-транзакции handleOps | Внешняя транзакция попала в блок; внутри могут быть другие UserOperations |
| UserOperation receipt | После on-chain обработки конкретной operation | sender, nonce, gas, success/reason и связанные logs для данного userOpHash |
- Идентификатор
- userOpHash
- Где появляется
- Ответ bundler после принятия объекта
- Что доказывает
- Конкретные поля UserOperation, EntryPoint и chain domain; не inclusion
- Идентификатор
- transactionHash
- Где появляется
- После включения bundle-транзакции handleOps
- Что доказывает
- Внешняя транзакция попала в блок; внутри могут быть другие UserOperations
- Идентификатор
- UserOperation receipt
- Где появляется
- После on-chain обработки конкретной operation
- Что доказывает
- sender, nonce, gas, success/reason и связанные logs для данного userOpHash
userOpHash означает acceptance, а не перевод
Draft ERC-7769 рекомендует возвращать из eth_sendUserOperation userOpHash только после simulation и принятия объекта в локальный UserOperation pool этого bundler. До этого проверяются структура, поддерживаемый EntryPoint, account validation, paymaster и срок действия. Это диагностический слой поверх архитектуры smart account: bundler ещё может повторно проверить объект перед bundle и удалить его, если состояние изменилось.
Ошибка RPC отвечает, почему объект не приняли
| Сигнал | Слой | Что перепроверить |
|---|---|---|
| -32602 | Форма RPC | Обязательные поля, hex encoding и согласованные factory/paymaster fields |
| -32500 и AAxx | EntryPoint simulation | Полный message, sender, nonce, signature и prefund |
| -32501 | Paymaster validation | Адрес, policy, data, deposit и срок sponsorship |
| -32502 | Bundler validation rules | Запрещённые opcode/storage patterns и supported mempool |
| -32503 | Time range | validAfter, validUntil и время следующего блока |
| -32507 | Wallet signature | Account implementation, signer set и подписанный userOpHash |
- Сигнал
- -32602
- Слой
- Форма RPC
- Что перепроверить
- Обязательные поля, hex encoding и согласованные factory/paymaster fields
- Сигнал
- -32500 и AAxx
- Слой
- EntryPoint simulation
- Что перепроверить
- Полный message, sender, nonce, signature и prefund
- Сигнал
- -32501
- Слой
- Paymaster validation
- Что перепроверить
- Адрес, policy, data, deposit и срок sponsorship
- Сигнал
- -32502
- Слой
- Bundler validation rules
- Что перепроверить
- Запрещённые opcode/storage patterns и supported mempool
- Сигнал
- -32503
- Слой
- Time range
- Что перепроверить
- validAfter, validUntil и время следующего блока
- Сигнал
- -32507
- Слой
- Wallet signature
- Что перепроверить
- Account implementation, signer set и подписанный userOpHash
AA-префикс локализует класс: AA1 относится к созданию sender, AA2 — к account validation, AA3 — к paymaster validation. Но полный номер и текст нельзя переносить между версиями EntryPoint. Сначала сохраните raw RPC error, chain ID, EntryPoint address и весь объект без секретов; затем сопоставьте его с документацией именно поддерживаемой версии. Причину обычной Ethereum-транзакции reverted разбирают отдельно, потому что она уже прошла другой путь включения.
Null не различает pending, dropped и чужой bundler
eth_getUserOperationByHash может вернуть null для не включённого объекта; pending operation bundler также вправе не раскрывать. eth_getUserOperationReceipt возвращает данные после включения, иначе null. Поэтому один null не доказывает, что operation никогда не попадёт в bundle. Опросите исходный bundler, сохраните время acceptance и проверьте текущие nonce, paymaster state и EntryPoint. Если есть transactionHash, прочитайте события и логи Ethereum внутри его receipt.
| Факт | Классификация | Безопасное действие |
|---|---|---|
| send вернул error, hash не получен | Bundler не принял объект | Исправить доказанную причину и заново оценить gas/state до новой подписи |
| Hash получен, lookup/receipt null | Acceptance есть, inclusion не доказан | Проверить исходный bundler и account nonce; не создавать другой вызов вслепую |
| Receipt есть, success=false | Operation включена, целевое execution не удалось | Разобрать reason/logs и фактические state deltas; nonce уже мог измениться |
| Receipt есть, success=true | EntryPoint зафиксировал success operation | Сверить целевые события, balances и получателя; success не доказывает экономический смысл |
- Факт
- send вернул error, hash не получен
- Классификация
- Bundler не принял объект
- Безопасное действие
- Исправить доказанную причину и заново оценить gas/state до новой подписи
- Факт
- Hash получен, lookup/receipt null
- Классификация
- Acceptance есть, inclusion не доказан
- Безопасное действие
- Проверить исходный bundler и account nonce; не создавать другой вызов вслепую
- Факт
- Receipt есть, success=false
- Классификация
- Operation включена, целевое execution не удалось
- Безопасное действие
- Разобрать reason/logs и фактические state deltas; nonce уже мог измениться
- Факт
- Receipt есть, success=true
- Классификация
- EntryPoint зафиксировал success operation
- Безопасное действие
- Сверить целевые события, balances и получателя; success не доказывает экономический смысл
Повтор начинается с текущего состояния account
Минимальный recovery packet
- 1Зафиксируйте домен
Chain ID, sender, EntryPoint address/version, bundler endpoint и userOpHash должны относиться к одной попытке.
- 2Сохраните raw object
Nonce, callData, gas fields, fees, factory/paymaster data и signature нужны для воспроизведения; seed и private key не нужны.
- 3Разделите стадии
Запишите acceptance response, lookup, receipt и внешний transactionHash как отдельные наблюдения.
- 4Перечитайте state
Получите актуальный nonce через EntryPoint/account и проверьте balance/deposit paymaster до перестроения.
- 5Подписывайте новый hash осознанно
Изменение nonce, gas, paymaster, callData, EntryPoint или chain создаёт другой запрос и требует нового подтверждения.
Stop-сигналы
- неизвестны chain или EntryPoint, но предлагают увеличить gas и подписать снова;
- поддержка просит seed-фразу, private key или перевод на paymaster вручную;
- вместо raw bundler error сохранился только скриншот слова Failed;
- один внешний handleOps receipt принимают за успех всех вложенных operations;
- userOpHash ищут через случайный RPC-узел без ERC-4337 методов и объявляют потерянным.
Проверка завершена, когда другой человек воспроизводит chain, EntryPoint, raw UserOperation, ответ bundler и — если включение состоялось — отдельный receipt с success и внешним transactionHash. RPC-узел общего назначения полезен для блока и receipt bundle, но поддержка ERC-4337 методов у него должна быть подтверждена отдельно. До этой связки безопаснее остановить повтор, чем создавать второй экономически равный вызов с новым hash.
Источники
Мы используем прямые ссылки и фиксируем дату проверки. Полный текст чужих материалов не перепечатывается.
- ERC-4337 — Account Abstraction Using Alt Mempool Ethereum Improvement Proposals · Проверено 22 августа 2026 г. в 10:35 GMT+5
- ERC-7769 — JSON-RPC API for ERC-4337 Ethereum Improvement Proposals · Проверено 22 августа 2026 г. в 10:35 GMT+5
- ERC-4337 Docs — ERC-7562 bundler validation rules ERC-4337 Documentation · Проверено 22 августа 2026 г. в 10:35 GMT+5
- eth-infinitism — IEntryPoint.sol eth-infinitism · Проверено 22 августа 2026 г. в 10:35 GMT+5
