Skip to content

fix: align approval hooks and permit spender checks#7620

Draft
fairlighteth wants to merge 3 commits into
developfrom
deepsec/medium-04-approval-permit-integrity
Draft

fix: align approval hooks and permit spender checks#7620
fairlighteth wants to merge 3 commits into
developfrom
deepsec/medium-04-approval-permit-integrity

Conversation

@fairlighteth

@fairlighteth fairlighteth commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Addresses the MEDIUM approval/permit integrity findings in cowswap-frontend.

This PR makes the approval entry points behave consistently across classic, permit, ETH-flow, and Safe bundle paths:

  • Aligns allowance checks with the actual spender used for approval.
  • Routes permit, ETH-flow, and Safe bundle approval flows through the same injected widget onBeforeApproval gate.
  • Keys permit generation and permit support caches by spender so stale results cannot be reused across spender changes.
  • Avoids reusing default pre-generated permit data when a custom spender is being checked.
  • Adds focused regressions for permit generation, permit support lookup, and approval state changes.

To Test

  1. Run targeted frontend and permit checks
  • pnpm exec jest --config apps/cowswap-frontend/jest.config.mjs --runInBand --runTestsByPath apps/cowswap-frontend/src/modules/erc20Approve/hooks/useApproveCurrency.test.ts apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGeneratePermitInAdvanceToTrade.test.ts apps/cowswap-frontend/src/modules/permit/hooks/usePermitInfo.test.ts passes.
  • pnpm exec nx run permit-utils:test --runInBand --runTestsByPath libs/permit-utils/src/lib/generatePermitHook.test.ts libs/permit-utils/src/lib/getTokenPermitInfo.test.ts passes.
  • pnpm exec tsc --noEmit -p apps/cowswap-frontend/tsconfig.app.json passes.
  • pnpm exec tsc --noEmit -p libs/permit-utils/tsconfig.lib.json passes.
  1. Verify classic approval behavior
  • Load a trade that requires ERC20 approval and confirm the allowance check matches the spender actually used in the approval transaction.
  • In an injected widget setup with onBeforeApproval, confirm the hook fires before the approval proceeds.
  1. Verify permit and ETH-flow approval behavior
  • Use a permit-capable token and confirm the widget approval hook still fires before the approval path continues.
  • Use the ETH-flow approval path and confirm it also goes through the same approval gate.
  • If the widget rejects onBeforeApproval, confirm the approval flow stops in each path.
  1. Verify Safe bundle approval behavior
  • Trigger a Safe bundle flow that requires approval and confirm the widget approval hook is consulted before the bundle proceeds.
  • Reject the hook and confirm the bundle path does not continue.
  1. Verify stale permit protection
  • Change the spender-driving trade context quickly while a permit is being prepared.
  • Confirm an older permit result is not reused for the newer spender.
  • Confirm permit support detection is re-evaluated when the spender changes instead of reusing the previous spender's cached result.

Background

The report found several variants of the same problem: different approval paths had drifted apart, so widget hooks and spender assumptions were not applied uniformly.

This PR pulls those paths back toward one approval boundary and makes both permit generation and permitability checks spender-aware.

@vercel

vercel Bot commented Jun 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cowfi Ready Ready Preview Jun 7, 2026 8:42am
explorer-dev Ready Ready Preview Jun 7, 2026 8:42am
storybook Ready Ready Preview Jun 7, 2026 8:42am
swap-dev Ready Ready Preview Jun 7, 2026 8:42am
widget-configurator Ready Ready Preview Jun 7, 2026 8:42am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
cosmos Ignored Ignored Jun 7, 2026 8:42am
sdk-tools Ignored Ignored Preview Jun 7, 2026 8:42am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 13dec1d8-116b-4b55-83e3-17785eb2ccdf

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deepsec/medium-04-approval-permit-integrity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 6, 2026

Copy link
Copy Markdown

Deploying explorer-dev with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3567a3c
Status: ✅  Deploy successful!
Preview URL: https://7c5677ad.explorer-dev-dxz.pages.dev
Branch Preview URL: https://deepsec-medium-04-approval-p.explorer-dev-dxz.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 6, 2026

Copy link
Copy Markdown

Deploying swap-dev with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3567a3c
Status: ✅  Deploy successful!
Preview URL: https://9f018ca0.swap-dev-5u6.pages.dev
Branch Preview URL: https://deepsec-medium-04-approval-p.swap-dev-5u6.pages.dev

View logs

- key permit support caches by spender
- bypass default pre-generated permit data for custom spenders
- restore eth-flow approval typing so app checks pass

@fairlighteth fairlighteth left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

AI Review (Codex GPT-5, worked 4m): no new non-duplicate findings

Review completed. I found no new non-duplicate comments worth posting.

Review scope and related context

Related context checked:

  • usePermitInfo, permittableTokensAtom, and getTokenPermitInfo: current code now keys permit support lookup/cache by spender and avoids reusing default pre-generated permit data for custom spenders.
  • Approval-gate call sites in classic approval, permit pre-generation, ETH-flow, and Safe bundle paths: current diff looks internally consistent with the updated PR description.
  • Existing PR comments: only bot/deploy comments are present, so there were no active human review threads to de-duplicate against.

@fairlighteth

Copy link
Copy Markdown
Contributor Author
PR - Automated QA Scope Pass (Codex GPT-5, worked 45m): hooks composer + spender-cache behavior verified

Outcome

  • ✅ Passed: disconnected hooks composer verified on the PR runtime path in Chromium and Firefox
  • ✅ Passed: wallet-connected-ui Hook Store flow verified in Chromium on Sepolia with a mocked injected EIP-1193 provider
  • ✅ Passed: spender-aware permit-cache logic verified on the PR build with a deterministic browser fixture
  • ✅ Scope note: this pass covered the hooks route, Hook Store shell, and spender-cache runtime path; intentionally untested QA items are listed below
  • ⚠️ Follow-up note: Permit a token was not surfaced in Hook Store UI, so that path was verified via browser harness rather than direct form interaction

At a glance

  • Source: local Playwright run against PR head 3567a3c3e2ca4d50546b0af8051339067ee97fc3
  • Browsers: Chromium 140.0.7339.16 and Firefox 141.0
  • OS: Linux
  • Wallet states:
    • disconnected: yes
    • provider-injected: yes
    • wallet-connected-ui: yes
    • signing-capable: no

Source under test

  • Browser-based verification was performed locally with Playwright against the local worktree at the PR head SHA.
  • A PR Vercel preview was checked first, but the final verification used the local app because the interactive trade surface was not reliably rendered there in headless mode.
  • Results were visually inspected from captured screenshots.

🔁 Re-run

  • Frontend: pnpm start:cowswap
  • Routes:
    • http://127.0.0.1:3004/#/1/swap/hooks
    • http://127.0.0.1:3004/#/11155111/swap/hooks
  • Local state required:
    • localStorage["redux_localstorage_simple_user"] = {"hooksEnabled":true,"matchesDarkMode":false,"userDarkMode":null,"userLocale":null}
  • Fixtures/mocks:
    • mocked injected EIP-1193 provider for the wallet-connected-ui Sepolia pass
    • deterministic browser harness against https://ethereum-rpc.publicnode.com for the spender-cache proof

Expected results:

  1. Open the hooks route and click Swap now
    Expected: the hooks composer loads with Add Pre-Hook Action and Add Post-Hook Action
  2. On Sepolia with the mocked provider, open Add Pre-Hook Action
    Expected: Hook Store opens in wallet-connected-ui state and renders the hook list modal cleanly
  3. Run the deterministic spender-cache harness on the PR build
    Expected: same-spender checks stay deduped, while different spenders trigger separate permit checks for the same token

🧪 Browser coverage

  • Chromium 140.0.7339.16
    • disconnected hooks composer
    • wallet-connected-ui Hook Store on Sepolia
    • ✅ deterministic spender-cache proof
  • Firefox 141.0
    • disconnected hooks composer

Why these adjacent flows were included:

  • The hooks composer route shares the same trade container and hook-entry shell touched by the spender-aware permit changes.
  • The Sepolia Hook Store pass exercises the wallet-aware modal/container path adjacent to the PermitHookApp consumer even though the permit dapp itself was not surfaced.
  • The deterministic browser harness directly exercises the shared permit-utils request-cache boundary changed by the PR, which is the critical stale-spender failure mode.

🖼️ Artifacts
Chromium disconnected hooks composer
Chromium disconnected hooks composer

Chromium wallet-connected-ui Hook Store on Sepolia
Chromium wallet-connected Hook Store on Sepolia

Firefox disconnected hooks composer
Firefox disconnected hooks composer

Note: Permit hook UI was not directly reachable

Impact:

  • This does not materially undercut the PR claim because the changed spender-cache logic was still exercised directly in-browser on the PR build.

Observed behavior:

  • Permit a token did not appear in the Hook Store lists on the tested mainnet or Sepolia routes.
  • The broader hooks route and Hook Store UI still rendered correctly.

Interpretation:

  • This looks separate from the spender-aware cache change itself.
QA Scope Not Covered (2)
  • PermitHookApp itself was not directly visible in Hook Store UI during this run
  • No signing-capable approval, signature, or order-submission flow was exercised
Commands + Setup

Commands run:

  • pnpm start:cowswap
  • PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/ms-playwright-local node - <<'NODE' ... NODE for the Chromium disconnected hooks-composer pass
  • PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/ms-playwright-local node - <<'NODE' ... NODE for the Chromium mocked-provider wallet-connected-ui Sepolia Hook Store pass
  • PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/ms-playwright-local node - <<'NODE' ... NODE for the Chromium browser-executed deterministic permit-cache harness against mainnet RPC
  • PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/ms-playwright-local node - <<'NODE' ... NODE for the Firefox disconnected hooks-composer smoke pass

Environment normalization used:

  • Playwright locale normalized to en-US
  • Chromium launched with --lang=en-US

Still manual if desired:

  • Human UX review of Hook Store availability/filtering for Permit a token
  • A true signing-capable approval or swap submission with a real wallet/session

Residual gaps:

  • The actual PermitHookApp form remains unproven through direct UI interaction in this run.
  • No real-wallet signing path was exercised.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant