Repository navigation
Fix email registration failures: title sanitization, AA24 VGL bump/retry, diagnostics - #20
Merged
Merged
Conversation
Titles copied from Medium contain invisible U+200A hair spaces around dashes. The circuit hashes the raw subject bytes while parseEmail collapses all Unicode whitespace, so the callData title and the proof's titleHash disagreed -> TitleHashMismatch on registration. Normalize the title (strip zero-width chars, collapse Unicode whitespace) before building the subject, the ID keccak, and validation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pimlico's send-time simulation rejected a provably valid registration UserOp with AA24 at verificationGasLimit 3.2M (fork replay of validateUserOp returns 0 at 3.2M; the same flow with 4M was accepted and landed: tx 0x5ecbbc764f0a8adc9dd1e89c6a23f91057f394924f7dfb8aa4b736cbe67b66b7). - raise PREDEFINED_VGL_BASE 3.2M -> 4M - email flow retries once with PREDEFINED_VGL + 1M on AA24, regenerating the proof since the userOpHash commits to the gas limits See incidents/2026-06-06-email-registration-failures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s for register.ts The bundler's VGL estimate is unreliable for this account: validateUserOp checks the userOpHash last and EmailVerifier swallows OOG in try/catch, so the binary search can terminate on the cheap "verify OOG'd -> SIG_VALIDATION_FAILED" path (observed raw 1,327,210 on Base with a real proof, far below the ~3.0M verify cost). The estimation script now also bisects the faithful-EVM minimum via eth_call of validateUserOp as the EntryPoint and recommends 1.4x of the max of both numbers. register.ts gains a chain-id argument (8453 support) and a --vgl override for testing bundler gas headroom. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generalized from the 2026-06-06 incident investigation: - verify-email-proof.ts: generate a proof locally and verify it against the deployed EmailVerifier via eth_call, bypassing the bundler -- separates proof/circuit/verifier issues from 4337-layer issues - check-userop-hash.ts: compare sendop's op.hash() against EntryPoint v0.8 getUserOpHash for an op built exactly like the frontend flow - docs/email-op-diagnostics.md: decision guide for TitleHashMismatch / AA24 failures, incl. how to replay a failed op from a user console log Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rtem Full post-mortem of the email registration failures (TitleHashMismatch from invisible hair spaces; spurious AA24 from Pimlico rejecting a valid op at VGL 3.2M; misleading VGL estimation), with evidence artifacts: the user's exact failed op (its proof verifies true on-chain and its baked userOpHash matches the EntryPoint), console log, and fork tests replaying validateUserOp success at VGL 3.2M pinned to a pre-registration block. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The incident replay tests require a Base mainnet fork; CI runs forge test without one, failing with "call to non-contract address". Skip when no code is deployed at the RAC address; forked runs still execute. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the three bugs behind the 2026-06-06 email registration failures on Base (full post-mortem with evidence artifacts in
incidents/2026-06-06-email-registration-failures/):TitleHashMismatch— invisible Unicode in titles. Titles copied from Medium contain U+200A hair spaces; the circuit hashes raw subject bytes whileparseEmailcollapses Unicode whitespace, so the two sides disagreed. The Email Generator now sanitizes titles (strip zero-width chars, collapse Unicode whitespace) before building the subject and theID:keccak.Spurious
AA24— Pimlico rejecting a valid op at VGL 3.2M. The user's exact failed op was proven valid (its proof verifiestrueon the deployed verifier, its baked userOpHash matches EntryPointgetUserOpHash, and a fork replay ofvalidateUserOpat VGL 3.2M returns 0), yeteth_sendUserOperationrejected it; the identical flow with VGL 4M landed (tx).PREDEFINED_VGL_BASEis raised to 4M and the email flow now retries once with +1M on AA24 (regenerating the proof, since the userOpHash commits to gas limits).Misleading VGL estimation. Because
validateUserOpchecks the userOpHash last andEmailVerifierswallows OOG intry/catch, the bundler's binary search can settle on the cheap OOG path (observed raw 1,327,210 with a real proof vs the ~3.0M real verify cost). The estimation script now also bisects the faithful-EVM minimum viaeth_calland recommends 1.4× of the max of both numbers.Also included
frontend/scripts/verify-email-proof.ts+frontend/scripts/check-userop-hash.ts— generalized diagnostic scripts from the investigation, with a decision guide indocs/email-op-diagnostics.mdregister.tsgains a chain-id argument and--vgloverrideincidents/folder with the post-mortem, the failed op + proof artifacts (credential-free), and fork tests (test/DebugUserOpReplay.t.sol,test/DebugEmail3VGL.t.sol) pinned to a pre-registration blockTest plan
forge fmt --checkclean; fork tests pass at--fork-block-number 46967000bun run check— no new errors (26 pre-existing.vueresolution errors)bun build🤖 Generated with Claude Code