chore(cleanup): Codex-gated cleanup (Tier A) + B1 codehash enforcement#22
Merged
Conversation
…consolidation
Codex-plan-reviewed, behavior-preserving. Each claim verified in-code first.
- A1 dead code: delete zero-consumer re-export aliases pathEnumerator.ts
enumeratorDomainForChainId (+ its orphaned comment) and url.ts PayMode re-export
(all consumers import PayMode from lib/fee; url.ts keeps its internal import).
- A2 weak types: stats/route.ts isAggregable -> type guard, drop 3 now-redundant
casts (chainId/tokenAddress/result narrowed); circleSend.ts drop redundant
alias-to-alias `as SignedCircleUserOp` (FSM `as Hex` assertions untouched).
- A3.1 types: execute.ts inline {attestation,signature} x3 -> AttestationResponse
from ./types (already imported; IRIS {message,attestation} shapes left alone).
- A3.3 types: history HistoryProvider/CircleVerification now alias the paymentLog
SoT (PaymentProvider/CircleVerificationStatus); fixed the inaccurate "circular
import" comment (history->paymentLog is one-directional, verified acyclic).
- A3.2 (BatchCall relocation) deferred: audit premise was wrong (simpleAccount has
no BatchCall; mav2 imports neither) -> would add a new module edge for a trivial
1-line type; not worth it on payment-adjacent modules.
Verified: tsc 0, madge 0 cycles, eslint clean, full suite 2532 passed/0 failed
(6 OOM files unchanged in allowlist).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rId in gas-quote hooks Behavior-equivalent DRY, verified in-code (Codex-gated). - pad(): hoist the 3 byte-identical `(n)=>n.toString().padStart(2,'0')` copies (history formatHistoryTimestamp / historyCsv filename / SuccessOverlay) into lib/format.ts. gateway.ts toString(16) hex formatting left untouched (different). Added pad equivalence tests (zero / 2-digit / 3+-digit boundary). - chainObjectForId(): replace the inline `supportedChains.find(c=>c.id===id)` in useGasQuoteUsdc/useGasQuoteCircle with the existing helper — byte-identical expression incl. unsupported-chainId -> undefined (verified by reading the impl). Verified: tsc 0, eslint clean, madge 0 cycles, full suite 2535 passed/0 failed (+3 pad tests; 6 OOM files unchanged in allowlist). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…xport+stats routes The two admin log endpoints had byte-identical Bearer-auth + KV-config guards (3 branches). Extracted into app/api/log/payment/_auth.ts (underscore = not a Next route) so the security-relevant auth has one tested source and cannot drift. Per Codex's "tests before extraction": added tests/app/api/log-payment-export.test.ts (export route previously had NO tests) asserting byte-identical status + error body for all branches; verified it passes against the pre-extraction route first, then extracted. Stats route already had auth tests (47) — unchanged after wiring. - _auth.ts: requireAdminAuth(req): NextResponse|null (503 admin_token_not_configured / 401 unauthorized / 503 kv_not_configured / null). Imports isKvConfigured from @/lib/kv (test mocks still apply module-wide). - export+stats routes: replace inline auth with `const e=requireAdminAuth(req); if(e)return e;` and drop the now-unused isKvConfigured import. Verified: tsc 0, eslint clean, route auth tests 53 pass, full suite 2541 passed/0 failed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ified) + gate script Codex-gated: do not hardcode an unverified value; verify every Circle chain, compare by deployment class, enforce only on full match (wrong value = fail-closed outage). - scripts/verify-circle-codehash.mjs: read-only gate (no keys/funds). eth_getCode on the v0.8 paymaster across all 14 Circle chains (7 mainnet + 7 testnet), asserts non-empty before hashing, compares keccak256 per deployment class. 2026-05-31 run: ALL 14 identical = 0x6ed62b6e...68f78a6a (mainnet == testnet; deterministic CREATE2). - circlePermit.ts: populate CIRCLE_PAYMASTER_CODEHASH for the explicitly-verified chainIds -> assertCirclePaymasterDeployed now enforces keccak256(code) match (C3). Explicit list (not derived from the address map) so a future chain isn't auto-enforced unverified; re-run the gate to add chains. - circleAccount.test.ts: the C3 "non-empty code passes" test now asserts codehash MISMATCH throws (421614 is registered); match path is the on-chain-verified prod path. - run-tests.mjs: record the refined Tier C OOM diagnosis (render-phase, not module-eval; boundaries already mocked) so the e2e-fenced known-limitation isn't re-chased. Verified: tsc 0, eslint clean, circleAccount 9 pass, full suite 2541 passed/0 failed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ess fence, pad module Phase-2 review fixes (Codex REVISE): - BLOCKER scripts/verify-circle-codehash.mjs: `uniform` ignored `missing`, so 1-success/ 6-fail would falsely report "all match" and never fail. Now require full coverage (missing.length===0 && single hash) per deployment class, add fallback RPCs (Polygon), and exit non-zero on any miss/divergence. Re-ran: all 14 chains reached, GATE PASS. - WARNING completeness: circlePaymaster.test.ts now asserts every CIRCLE_PAYMASTER_ADDRESSES chain has a CIRCLE_PAYMASTER_CODEHASH entry, so no allowlisted Circle chain can silently skip hash validation. - WARNING proxy caveat: circlePermit.ts comment clarifies codehash pins runtime bytecode (auxiliary; address allowlist is primary; proxy shells aren't impl-pinned). - WARNING recovery: runbook documents the codehash-mismatch fail-closed recovery (flag off -> Pimlico -> re-run gate -> update codehash). - NIT bundle: moved pad() from lib/format.ts (imports viem) to viem-free lib/pad.ts so the /pay-baseline consumers (SuccessOverlay/history) don't drag viem in. (Note: /pay is at the 420kB edge on main too — pre-existing platform delta, not a regression from this branch.) Verified: tsc 0, eslint clean, full suite 2542 passed/0 failed, codehash gate exit 0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…loud on missing codehash - verify-circle-codehash.mjs: production stores ONE universal codehash for all chains, so the gate now requires mainnet.hash === testnet.hash (cross-class) in the pass condition, not just per-class uniformity. Re-ran: GATE PASS (all 14 + cross-class same). - circlePermit.ts: assertCirclePaymasterDeployed now THROWS when a chain has no codehash entry (was silent non-empty-only skip). The completeness test guarantees all allowlisted Circle chains are pinned, so absence = misconfiguration -> fail-loud. - smoke-circle-crossswitch.mjs: update the stale "enforcement はまだ" comment (codehash enforcement is active since 2026-05-31). Verified: gate exit 0, tsc 0, eslint clean, full suite 2542 passed/0 failed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tandard-mode caveat - Gasless now: Pimlico (JPYC sponsorship / USDC erc20) OR Circle Paymaster v0.8 for USDC on Base/Arbitrum/Optimism (USDC-native gas, OpenPay 0 fee). - Avalanche C-Chain: standard-mode only until EIP-7702 (ACP-209) activates on mainnet; gasless gracefully falls back (merchant pay) / fans guided to another chain (tips). Corrects the prior "gasless on all 6 merchant chains" claim. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Codex-gated cleanup + trust-boundary hardening. Plan reviewed (approve), code reviewed (approve). Each unit verified (tsc / eslint / madge 0 cycles / full suite) and the production build + bundle budget.
What's in (7 commits)
Tier A — behavior-preserving cleanup (audit-verified, in-code-confirmed):
enumeratorDomainForChainId,url.tsPayMode).isAggregable→ type guard + 3 redundant casts dropped; redundantas SignedCircleUserOpdropped (FSMas Hexuntouched).AttestationResponse, history/paymentLog provider unions (SoT = paymentLog).pad()→ viem-freelib/pad.ts;chainObjectForId()in gas-quote hooks;requireAdminAuth()shared by export+stats routes (+ new export-route auth tests).B1 — Circle Paymaster codehash enforcement (trust boundary):
scripts/verify-circle-codehash.mjs— read-only cross-chain gate (eth_getCodeon all 14 Circle chains, per-class non-empty+uniform, cross-class equality, fail-closed non-zero exit). Ran 2026-05-31: all 14 identical =0x6ed62b6e…68f78a6a.CIRCLE_PAYMASTER_CODEHASHpopulated (explicit verified chainIds) →assertCirclePaymasterDeployednow enforceskeccak256(code)match; throws on a missing entry (fail-loud); completeness test fences every allowlisted chain.Deferred by design (not in this PR)
A3.2BatchCall relocation (would add a module edge for a trivial type).appendFromCtx(payment-history call sites are non-uniform).run-tests.mjs.Verification
tsc --noEmit✅ ·eslint✅ ·madge --circular✅ 0 cycles · full suite 2542 passed / 0 failed · codehash gate exit 0./paysits at the 420 kB edge on main too (pre-existing platform delta) — this branch adds 0 kB to/pay.🤖 Generated with Claude Code