Skip to content

fix: keep the EIP-7702 initCode marker in UserOperation.toPacked - #574

Closed
erkancamli wants to merge 1 commit into
wevm:mainfrom
erkancamli:fix/user-operation-7702-init-code
Closed

erkancamli wants to merge 1 commit into
wevm:mainfrom
erkancamli:fix/user-operation-7702-init-code

Conversation

@erkancamli

Copy link
Copy Markdown
Contributor

UserOperation.toInitCode always replaces a 0x7702 factory with the authorization's delegate address:

if (!authorization) return '0x7702000000000000000000000000000000000000'
const delegation = authorization.address
return Hex.concat(delegation, factoryData ?? '0x')

and toPacked uses it for the packed user operation, the form the AA guide passes to the EntryPoint. EntryPoint 0.8 and 0.9 (Eip7702Support) only treat an operation as EIP-7702 when the first 20 bytes of initCode equal bytes20(0x7702), the marker padded with zeros; the delegate address is substituted only for hashing, in _getEip7702InitCodeHashOverride. With the delegate in initCode, the operation is not recognised as 7702: on 0.8 handleOps reverts with AA10 sender already constructed (the delegated sender already has code), and on 0.9 the init code is ignored, so factoryData never runs. The hash is unaffected, so the signature still verifies and nothing fails until the op is on chain. fromPacked(toPacked(op)).factory also comes back as the delegate rather than 0x7702.

viem fixed the same thing in 892ebea1 by giving getInitCode a forHash option. ox already has forHash on toPacked, but it only reaches the paymaster signature.

This adds forHash to toInitCode:

  • default: the 20-byte 0x7702 marker followed by factoryData (the short '0x7702' form is padded too, so the EntryPoint check matches);
  • forHash: true: the delegate form used for hashing, as today.

toPacked passes its forHash on, so hash (which packs with forHash: true) gives the same 0.8 and 0.9 hashes as before, matching viem.

Tests: toPacked > eip7702 covers the default packed initCode and the round trip through fromPacked, plus the forHash form; the existing delegate-form toInitCode cases now pass { forHash: true }. On main the new default cases fail with the delegate address in place of the marker; with this change the src/erc4337 tests pass. vp check is clean on the changed files. A changeset is included.

Note that this changes the default output of the public toInitCode for EIP-7702 operations, the same change viem made for getInitCode.

`toInitCode` always replaced the `0x7702` factory with the
authorization's delegate address, and `toPacked` used it for the
packed user operation sent to the EntryPoint. EntryPoint 0.8 and 0.9
only treat an operation as EIP-7702 when the first 20 bytes of
`initCode` are the `0x7702` marker; the delegate address belongs only
in the hashed form (`_getEip7702InitCodeHashOverride`). With the
delegate in place, 0.8 reverts with "AA10 sender already constructed"
and 0.9 ignores the initCode, skipping `factoryData`.

`toInitCode` now takes a `forHash` option, as viem's `getInitCode`
does: without it the init code is the padded marker followed by
`factoryData`, with it the delegate form used for hashing. `toPacked`
passes its own `forHash` on, so `hash` is unchanged.
@vercel

vercel Bot commented Nov 3, 2026

Copy link
Copy Markdown

@erkancamli is attempting to deploy a commit to the Wevm Team on Vercel.

A member of the Team first needs to authorize it.

jxom commented Nov 8, 2026

Copy link
Copy Markdown
Member

Thanks @erkancamli, the fix is correct. Superseded by #593 (main, which keeps your commit) and #594 (0.x backport), with small follow-ups to the changeset and tests.

@jxom jxom closed this Nov 8, 2026
jxom added a commit that referenced this pull request Nov 8, 2026
)

Backports #574 to 0.x. `toInitCode` replaced the `0x7702`
factory with the authorization's delegate address, so `toPacked`
produced an initCode that EntryPoint 0.8 does not recognise as
EIP-7702 and rejects with "AA10 sender already constructed".

`toInitCode` and `toPacked` now take a `forHash` option: by default the
init code is the padded `0x7702` marker followed by `factoryData`; with
`forHash` it is the delegate form the EntryPoint hashes. `toTypedData`
(and so `hash`) packs with `forHash`, so hashes are unchanged.


Amp-Thread-ID: https://ampcode.com/threads/T-01a1bc8e-ad8f-7187-b41f-f8092b65ad6b

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: ecamli <107792368+erkancamli@users.noreply.github.com>
Co-authored-by: jxom <jake@tempo.xyz>
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