Skip to content

fix(executor): preserve 2-byte 0x7702 EIP-7702 marker when packing initCode - #8

Merged
Ghadi8 merged 2 commits into
developfrom
fix/eip7702-initcode-padding
Aug 4, 2026
Merged

Ghadi8 merged 2 commits into
developfrom
fix/eip7702-initcode-padding

Conversation

@AngeloAyranji

Copy link
Copy Markdown

Problem

EIP-7702 userOps that carry a paymaster are accepted by eth_sendUserOperation and then silently deleted at bundle time ("failed on chain estimation. deleting..."), never mining. Self-funded 7702 ops and non-7702 paymaster ops are unaffected.

Root cause

packUserOp right-pads op.factory to 20 bytes unconditionally (packedUserOpUtils.ts), turning the EIP-7702 marker 0x7702 into 0x7702 + 18 zero bytes. Paymasters that commit to keccak256(userOp.initCode) — e.g. Pimlico's singleton (SingletonPaymasterV7.sol:356, inherited by V8) — signed over the canonical 2-byte form, so the re-packed op fails paymaster signature validation with FailedOp("AA34 signature error") inside validateBundle's eth_estimateGas, and the op is cancelled without any client-visible error.

The account signature is unaffected because the EntryPoint normalizes initCode in its own userOpHash for 7702 ops (UserOperationLib.sol:48) — which is why only the paymaster combination dies (always AA34, never AA24).

Evidence

  • Prod log (bundler-base-sepolia, 2026-08-04 08:45:58 UTC): op 0x04d50f8c… deleted with FailedOp(0, "AA34 signature error") from the bundle estimation.
  • Byte-level A/B on Base Sepolia via Alchemy, same op, same node, same second: handleOps estimation with 2-byte initCode passes (0x615b3 gas); identical op with the 20-byte padded initCode reverts AA34 signature error.
  • On-prod behavior matrix: 7702 self-funded → mined; 7702 + paymaster → silently dropped; paymaster from already-delegated EOA → mined.

Fix

Guard the pad with the exported INITCODE_EIP7702_MARKER constant (case-folded). Real 20-byte factory addresses take the identical path as before (the pad was a no-op for them).

Tests

New packedUserOpUtils.test.ts (5 cases): marker stays 2 bytes, odd-cased marker, marker + factoryData concatenation, real factory address unchanged, no factory → 0x. The 7702 cases were written first and observed failing with the padded output before the fix (TDD). tsc build clean; the executor suite's 8 pre-existing failures (anvil-dependent fixtures) are identical on clean develop.

Note

Upstream etherspot/skandha master has the same unconditional padding (hexRightPad(op.factory ?? "0x", 20)), so this is worth an upstream issue/PR as well.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SDWq76gdRTBEsNF6u6yJq7

@justalab-agents justalab-agents Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR fixes a bug where the EIP-7702 0x7702 marker in a UserOperation's factory field was being right-padded to 20 bytes during packing, invalidating paymaster signatures that commit to keccak256(initCode) and causing bundle-time AA34 reverts. The fix preserves the 2-byte marker as-is and adds unit tests covering normal factory addresses, the EIP-7702 case, and edge cases.

One thing the inline comments don't make obvious: the corresponding unpackUserOp function has a symmetrical gap — it still blindly slices 20 bytes for the factory address, which will misparse (or error on) any packed op using the 2-byte EIP-7702 marker, breaking the pack→unpack round-trip.

✅ No blocking issues found by the automated review — this is not a substitute for human review.

@Ghadi8
Ghadi8 merged commit 2f3c76e into develop Aug 4, 2026
3 of 4 checks passed
@Ghadi8
Ghadi8 deleted the fix/eip7702-initcode-padding branch August 4, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants