Skip to content

Conversation

@shoom3301
Copy link
Collaborator

@shoom3301 shoom3301 commented Oct 23, 2025

Summary

Fixes https://www.notion.so/cownation/App-asks-to-approve-a-partial-amount-when-token-is-approved-2878da5f04ca801e8a0fc4e4d00cea04?source=copy_link

To Test

  1. See https://www.notion.so/cownation/App-asks-to-approve-a-partial-amount-when-token-is-approved-2878da5f04ca801e8a0fc4e4d00cea04?source=copy_link
  2. I also removed "Current allowance" displaying :(

Summary by CodeRabbit

  • Bug Fixes

    • Removed the current allowance display from the approval flow for improved clarity.
  • Improvements

    • Enhanced partial approval amount validation and input handling for better accuracy.

@shoom3301 shoom3301 requested review from a team October 23, 2025 12:40
@shoom3301 shoom3301 self-assigned this Oct 23, 2025
@vercel
Copy link

vercel bot commented Oct 23, 2025

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

Project Deployment Preview Updated (UTC)
cowfi Ready Ready Preview Nov 3, 2025 11:17am
explorer-dev Ready Ready Preview Nov 3, 2025 11:17am
swap-dev Ready Ready Preview Nov 3, 2025 11:17am
widget-configurator Ready Ready Preview Nov 3, 2025 11:17am
2 Skipped Deployments
Project Deployment Preview Updated (UTC)
cosmos Ignored Ignored Nov 3, 2025 11:17am
sdk-tools Ignored Ignored Preview Nov 3, 2025 11:17am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 23, 2025

Walkthrough

This PR threads a new amountToSwap prop through the ERC20 approval modal chain for amount-based validation, renames initialAmount to initialApproveAmount in ApprovalAmountInput, replaces atom-based partial-approval checks with a hook-based approach, and removes the TradeAllowanceDisplay component.

Changes

Cohort / File(s) Summary
Approval Modal Components
modules/erc20Approve/containers/PartialApproveAmountModal/PartialApproveAmountModal.tsx, modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModal.tsx, modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModalPure.tsx, modules/erc20Approve/containers/TradeChangeApproveAmountModal/TradeChangeApproveAmountModal.tsx
Added amountToSwap prop to modal component signatures; updated ChangeApproveAmountModalPure to pass initialApproveAmount and amountToSwap to ApprovalAmountInput; TradeChangeApproveAmountModal now reads maximumSendSellAmount and passes it as amountToSwap to ChangeApproveAmountModal
Approval Input & Amount Computation
modules/erc20Approve/containers/ApprovalAmountInput/ApprovalAmountInput.tsx, modules/erc20Approve/containers/PartialApproveContainer/PartialApproveContainer.tsx, modules/erc20Approve/containers/Erc20ApproveWidget/index.tsx
Replaced initialAmount with initialApproveAmount and added amountToSwap prop to ApprovalAmountInput; updated validation logic to compare against amountToSwap; PartialApproveContainer computes finalAmountToApprove based on partial-approval mode and passes amountToSwap={amountToApprove} to modal; Erc20ApproveWidget added logic to reset user-set approve amount when trade amounts change
Hook & State Management
modules/erc20Approve/state/customApproveAmountInputState.ts, modules/erc20Approve/hooks/useGetAmountToSignApprove.tsx
Wrapped reset function with useCallback for memoization; replaced Jotai atom usage with useIsPartialApprovalModeSelected hook
Approval Logic & Display
modules/erc20Approve/containers/TradeApproveWithAffectedOrderList/TradeApproveWithAffectedOrderList.tsx
Removed currentAllowance handling and TradeAllowanceDisplay UI rendering; replaced atom-based partial-approval check with useIsPartialApprovalModeSelected hook
Parent Component
account/containers/OrderPartialApprove/OrderPartialApprove.tsx
Added amountToSwap={amountToApprove} prop to PartialApproveAmountModal; added TODO comment
Removed Components
modules/erc20Approve/pure/TradeAllowanceDisplay/index.tsx, modules/erc20Approve/pure/TradeAllowanceDisplay/styled.ts
Deleted TradeAllowanceDisplay component and all associated styled exports

Sequence Diagram

sequenceDiagram
    participant OrderPartialApprove as OrderPartialApprove
    participant PartialApproveAmountModal as PartialApproveAmountModal
    participant ChangeApproveAmountModal as ChangeApproveAmountModal
    participant ChangeApproveAmountModalPure as ChangeApproveAmountModalPure
    participant ApprovalAmountInput as ApprovalAmountInput

    OrderPartialApprove->>PartialApproveAmountModal: amountToSwap={amountToApprove}<br/>initialAmountToApprove=...
    PartialApproveAmountModal->>ChangeApproveAmountModal: amountToSwap={amountToSwap}
    ChangeApproveAmountModal->>ChangeApproveAmountModalPure: amountToSwap={amountToSwap}
    ChangeApproveAmountModalPure->>ApprovalAmountInput: initialApproveAmount={initialAmount}<br/>amountToSwap={amountToSwap}
    
    Note over ApprovalAmountInput: customAmountValue = userValue ??<br/>initialApproveAmount ?? amountToSwap
    Note over ApprovalAmountInput: isInvalid = amountToSwap ?<br/>value.lessThan(amountToSwap) : false
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Prop threading consistency: Verify that amountToSwap is correctly passed through the entire modal chain and that all usages align with the new prop names
  • ApprovalAmountInput validation logic: Confirm the updated fallback chain (userValue ?? initialApproveAmount ?? amountToSwap) is semantically correct and handles null/undefined cases properly
  • Erc20ApproveWidget effects: Validate that the two new useEffect hooks (one for resetting amounts, one for storing partial-approval state) don't create circular dependencies or memory leaks
  • Hook replacement: Ensure useIsPartialApprovalModeSelected replaces all atom-based flag checks and works consistently across components
  • Removed component: Confirm TradeAllowanceDisplay removal doesn't break existing tests or imports elsewhere

Possibly related PRs

  • cowprotocol/cowswap#6351 — Introduced the partial-approval component chain that this PR extends by threading the amountToSwap prop
  • cowprotocol/cowswap#6411 — Changed partial-approval mode checking across the same approval components using the useIsPartialApprovalModeSelected hook
  • cowprotocol/cowswap#6224 — Prior partial-approve/permit work that this PR builds upon with additional prop wiring and modal signature updates

Suggested reviewers

  • elena-zh
  • shoom3301

Poem

🐰 Through modals they hop, props in a line,
amountToSwap threads where amounts align,
Old atoms fade—hooks now take their place,
Allowance displays vanish without a trace,
Approval flows faster, more graceful and clean!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description follows the template structure with Summary and To Test sections, but both are substantially incomplete. The Summary section lacks a high-level description of what changes are being made and instead only references an external Notion link without explaining the fix inline. The To Test section is particularly sparse, consisting merely of "See [link]" and a brief mention of removing "Current allowance" display, without providing actual step-by-step testing instructions or checkbox items for QA verification as specified in the template. While the external link provides context, the description itself should be self-contained enough that reviewers and QA personnel understand what to test without needing to access external resources. To improve the description, add a high-level explanation in the Summary section describing how the fix works (e.g., "Resets the custom approve amount state whenever the trade changes, preventing stale partial approval prompts from persisting"). In the To Test section, provide concrete steps such as "Enable partial approvals, execute a trade with a custom approval amount, then modify the input amount and verify the approval modal resets to the new target amount." Include checkbox items for specific behaviors to verify, such as "Verify the approve modal does not show outdated partial approval amounts after modifying trade inputs" and "Confirm the removal of the current allowance display does not affect approval functionality."
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "fix(approve): reset custom approve amount when trade changes" directly reflects the core fix being implemented, as evidenced by the new useEffect in Erc20ApproveWidget that resets the user-set approve amount whenever the trade target amount changes. This addresses the primary issue documented in the PR objectives where the app was incorrectly showing a partial approval prompt after a delay despite the token already being approved. The title is concise, specific, and clearly communicates the main objective from the developer's perspective. While the PR also includes supporting changes like adding the amountToSwap prop throughout the approval flow and removing the TradeAllowanceDisplay component, these are implementation details that enable the core fix rather than separate primary changes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/update-allowance-earlier

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.

Copy link
Contributor

@fairlighteth fairlighteth left a comment

Choose a reason for hiding this comment

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

Functionally (manual UI testing) it works for case:

(1) partial-approval flag on, (2) swap 6 COW → USDC where COW still needs approval, (3) set a custom allowance of 100 COW and confirm, (4) execute the swap so 94 COW allowance remains, (5) start a new swap for less than 94 COW. In that loop, it correctly recognized the existing 100 COW allowance and didn’t prompt for another approval.

Copy link
Contributor

@fairlighteth fairlighteth left a comment

Choose a reason for hiding this comment

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

Tested this scenario and here I do see an issue:

Problematic scenario: pick a token that needs approval, enable partial approvals, open the partial-approval modal, set a custom amount (say 100), and confirm. Without clearing that allowance, reopen the modal—e.g., click “Change approval amount.” Instead of showing the saved 100, the modal falls back to the current trade amount, so the user must re-enter their custom value.

@elena-zh
Copy link
Contributor

Hey @shoom3301 , apart the issue that @fairlighteth reported above, I have 1 question: is it OK that 'partial approval' block is displayed ~30-40 seconds after a trade, however, a token is already approved?
approved cow
Might it be possible to improve this?

Thank you!

@alfetopito
Copy link
Collaborator

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 27, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@limitofzero
Copy link
Contributor

Hey @shoom3301 , apart the issue that @fairlighteth reported above, I have 1 question: is it OK that 'partial approval' block is displayed ~30-40 seconds after a trade, however, a token is already approved? approved cow Might it be possible to improve this?

Thank you!

Could you correct me if I'm wrong. As I get it, you sign approve from another window?

It can be improved by integrating moralis api for allowance and reducing time for checking this allowance from the frontend side.

right now if an approve was signed not directly from "approve flow"(f.e. another window or somewhere else) we don't know that we should force allowance update

@limitofzero
Copy link
Contributor

@elena-zh @fairlighteth could you pls check again, I've added saving the amount if user once confirmed it

@elena-zh
Copy link
Contributor

Hey @limitofzero , thank you!

Could you correct me if I'm wrong. As I get it, you sign approve from another window?

No, from the same. I follow the steps to reproduce in the original issue, and after the 1st trade I still see 'approve and swap' even if a sell amount is already approved. This state is displayed up to 20-30 seconds.

It can be improved by integrating moralis api for allowance
we decided to stop using this service :(

Now, new issues that I've faced (all of them are recorded on this video)

  1. Enable the partial approvals setting ON
  2. Specify a swap with not approved permittable token
  3. Edit a permit amount --> set to a higher one, save changes
  4. Press on the edit button again and reduce an amount (by 1, as an example) --> error message appears (approval amount is less than sell amount), however, it is not.
  5. change an amount to a greater one
  6. Do NOT save changes, just press on the back button --> the permit amount is reset to the sell amount, the previous value is not stored.

Could you please fix it?

@limitofzero
Copy link
Contributor

@elena-zh thank you for checking, fixed

Base automatically changed from fix/affected-order-partial-approve to develop November 1, 2025 04:03
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/cowswap-frontend/src/modules/account/containers/OrderPartialApprove/OrderPartialApprove.tsx (1)

54-54: Valid observation on code duplication.

The TODO comment correctly identifies that OrderPartialApprove and PartialApproveContainer share similar logic. Consider consolidating this in a follow-up refactoring.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 479f61b and 0d20851.

📒 Files selected for processing (13)
  • apps/cowswap-frontend/src/modules/account/containers/OrderPartialApprove/OrderPartialApprove.tsx (1 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ApprovalAmountInput/ApprovalAmountInput.tsx (2 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModal.tsx (3 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModalPure.tsx (3 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/Erc20ApproveWidget/index.tsx (2 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveAmountModal/PartialApproveAmountModal.tsx (1 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveContainer/PartialApproveContainer.tsx (2 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveWithAffectedOrderList/TradeApproveWithAffectedOrderList.tsx (1 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeChangeApproveAmountModal/TradeChangeApproveAmountModal.tsx (1 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGetAmountToSignApprove.tsx (2 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/pure/TradeAllowanceDisplay/index.tsx (0 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/pure/TradeAllowanceDisplay/styled.ts (0 hunks)
  • apps/cowswap-frontend/src/modules/erc20Approve/state/customApproveAmountInputState.ts (2 hunks)
💤 Files with no reviewable changes (2)
  • apps/cowswap-frontend/src/modules/erc20Approve/pure/TradeAllowanceDisplay/index.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/pure/TradeAllowanceDisplay/styled.ts
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: limitofzero
Repo: cowprotocol/cowswap PR: 6351
File: apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts:87-121
Timestamp: 2025-10-13T19:41:31.440Z
Learning: In apps/cowswap-frontend/src/modules/erc20Approve, useApproveCallback returns Promise<TransactionResponse | undefined> and is distinct from useApproveCurrency, which can return Promise<TransactionReceipt | SafeMultisigTransactionResponse>. When reviewing approval flows, verify which hook is actually being used before flagging Safe wallet concerns.
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 5443
File: apps/cowswap-frontend/src/modules/swap/containers/ConfirmSwapModalSetup/index.tsx:71-71
Timestamp: 2025-02-20T15:59:33.749Z
Learning: The swap module in apps/cowswap-frontend/src/modules/swap/ is marked for deletion in PR #5444 as part of the swap widget unification effort.
Learnt from: fairlighteth
Repo: cowprotocol/cowswap PR: 6347
File: apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx:49-49
Timestamp: 2025-10-10T20:28:16.565Z
Learning: In apps/cowswap-frontend/src/modules/trade, TradeConfirmation follows a two-layer architecture: TradeConfirmationView (pure/stateless) in pure/TradeConfirmation/index.tsx renders the UI, while TradeConfirmation (container) in containers/TradeConfirmation/index.tsx wraps it to freeze props during pending trades (via useStableTradeConfirmationProps), wire in signing state (useSigningStep), and inject trade confirmation state (useTradeConfirmState). Consuming modules should import the container TradeConfirmation from 'modules/trade' to preserve this stateful behavior.
<!-- [add_learning]
When reviewing component refactoring in apps/cowswap-frontend/src/modules/trade, recognize the pattern where a pure view component (e.g., TradeConfirmationView) is separated from a stateful container (e.g., TradeConfirmation) that wraps it. The container adds runtime state management (prop stabilization, signing state, etc.) while the view remains testable and composable. Do not flag usages that import th...
📚 Learning: 2025-10-10T20:28:16.565Z
Learnt from: fairlighteth
Repo: cowprotocol/cowswap PR: 6347
File: apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx:49-49
Timestamp: 2025-10-10T20:28:16.565Z
Learning: In apps/cowswap-frontend/src/modules/trade, TradeConfirmation follows a two-layer architecture: TradeConfirmationView (pure/stateless) in pure/TradeConfirmation/index.tsx renders the UI, while TradeConfirmation (container) in containers/TradeConfirmation/index.tsx wraps it to freeze props during pending trades (via useStableTradeConfirmationProps), wire in signing state (useSigningStep), and inject trade confirmation state (useTradeConfirmState). Consuming modules should import the container TradeConfirmation from 'modules/trade' to preserve this stateful behavior.
<!-- [add_learning]
When reviewing component refactoring in apps/cowswap-frontend/src/modules/trade, recognize the pattern where a pure view component (e.g., TradeConfirmationView) is separated from a stateful container (e.g., TradeConfirmation) that wraps it. The container adds runtime state management (prop stabilization, signing state, etc.) while the view remains testable and composable. Do not flag usages that import th...

Applied to files:

  • apps/cowswap-frontend/src/modules/erc20Approve/containers/Erc20ApproveWidget/index.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGetAmountToSignApprove.tsx
  • apps/cowswap-frontend/src/modules/account/containers/OrderPartialApprove/OrderPartialApprove.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveWithAffectedOrderList/TradeApproveWithAffectedOrderList.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeChangeApproveAmountModal/TradeChangeApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveContainer/PartialApproveContainer.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveAmountModal/PartialApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ApprovalAmountInput/ApprovalAmountInput.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModalPure.tsx
📚 Learning: 2025-10-13T19:41:31.440Z
Learnt from: limitofzero
Repo: cowprotocol/cowswap PR: 6351
File: apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts:87-121
Timestamp: 2025-10-13T19:41:31.440Z
Learning: In apps/cowswap-frontend/src/modules/erc20Approve, useApproveCallback returns Promise<TransactionResponse | undefined> and is distinct from useApproveCurrency, which can return Promise<TransactionReceipt | SafeMultisigTransactionResponse>. When reviewing approval flows, verify which hook is actually being used before flagging Safe wallet concerns.

Applied to files:

  • apps/cowswap-frontend/src/modules/erc20Approve/containers/Erc20ApproveWidget/index.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGetAmountToSignApprove.tsx
  • apps/cowswap-frontend/src/modules/account/containers/OrderPartialApprove/OrderPartialApprove.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveWithAffectedOrderList/TradeApproveWithAffectedOrderList.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeChangeApproveAmountModal/TradeChangeApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveContainer/PartialApproveContainer.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveAmountModal/PartialApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ApprovalAmountInput/ApprovalAmountInput.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/state/customApproveAmountInputState.ts
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModalPure.tsx
📚 Learning: 2025-07-24T16:42:53.154Z
Learnt from: cowdan
Repo: cowprotocol/cowswap PR: 6009
File: apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/HighFeeWarning/HighFeeWarningTooltipContent.tsx:23-33
Timestamp: 2025-07-24T16:42:53.154Z
Learning: In apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/HighFeeWarning/HighFeeWarningTooltipContent.tsx, the use of toFixed(2) for percentage formatting in tooltip content is intentional and differs from the banner message formatting that uses toSignificant(2, undefined, Rounding.ROUND_DOWN). This formatting difference serves different UX purposes and should not be flagged as inconsistent.

Applied to files:

  • apps/cowswap-frontend/src/modules/erc20Approve/containers/Erc20ApproveWidget/index.tsx
  • apps/cowswap-frontend/src/modules/account/containers/OrderPartialApprove/OrderPartialApprove.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveWithAffectedOrderList/TradeApproveWithAffectedOrderList.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeChangeApproveAmountModal/TradeChangeApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveContainer/PartialApproveContainer.tsx
📚 Learning: 2025-02-20T15:59:33.749Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 5443
File: apps/cowswap-frontend/src/modules/swap/containers/ConfirmSwapModalSetup/index.tsx:71-71
Timestamp: 2025-02-20T15:59:33.749Z
Learning: The swap module in apps/cowswap-frontend/src/modules/swap/ is marked for deletion in PR #5444 as part of the swap widget unification effort.

Applied to files:

  • apps/cowswap-frontend/src/modules/erc20Approve/containers/Erc20ApproveWidget/index.tsx
  • apps/cowswap-frontend/src/modules/account/containers/OrderPartialApprove/OrderPartialApprove.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeChangeApproveAmountModal/TradeChangeApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveAmountModal/PartialApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModalPure.tsx
📚 Learning: 2025-08-12T05:57:08.021Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6138
File: libs/hook-dapp-lib/src/hookDappsRegistry.ts:1-1
Timestamp: 2025-08-12T05:57:08.021Z
Learning: The matchHooksToDapps function in libs/hook-dapp-lib/src/utils.ts provides backward compatibility for permit hooks through function selector detection (EIP_2612_PERMIT_SELECTOR and DAI_PERMIT_SELECTOR) rather than dappId matching, making it robust against dappId changes.

Applied to files:

  • apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGetAmountToSignApprove.tsx
📚 Learning: 2025-08-08T13:56:18.009Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6125
File: libs/tokens/src/updaters/TokensListsUpdater/index.tsx:29-31
Timestamp: 2025-08-08T13:56:18.009Z
Learning: In libs/tokens/src/updaters/TokensListsUpdater/index.tsx, the project’s current Jotai version requires using `unstable_getOnInit` (not `getOnInit`) in atomWithStorage options; keep `{ unstable_getOnInit: true }` until Jotai is upgraded.

Applied to files:

  • apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGetAmountToSignApprove.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/state/customApproveAmountInputState.ts
📚 Learning: 2025-08-08T13:55:17.528Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6125
File: libs/tokens/src/state/tokens/allTokensAtom.ts:78-78
Timestamp: 2025-08-08T13:55:17.528Z
Learning: In libs/tokens/src/state/tokens/allTokensAtom.ts (TypeScript/Jotai), the team prefers to wait for token lists to initialize (listsStatesListAtom non-empty) before returning tokens. No fallback to favorites/user-added/native tokens should be used when listsStatesList is empty.

Applied to files:

  • apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGetAmountToSignApprove.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/state/customApproveAmountInputState.ts
📚 Learning: 2025-06-23T07:03:50.760Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 5859
File: apps/cowswap-frontend/src/modules/tradeQuote/hooks/useTradeQuotePolling.ts:76-82
Timestamp: 2025-06-23T07:03:50.760Z
Learning: In the useTradeQuotePolling hook, there are two useLayoutEffect hooks that work together: one resets the counter to 0 when the confirmation modal closes, and another automatically triggers pollQuote(false, true) whenever the counter reaches 0. This creates an intentional chain reaction for immediate quote updates.

Applied to files:

  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveWithAffectedOrderList/TradeApproveWithAffectedOrderList.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeChangeApproveAmountModal/TradeChangeApproveAmountModal.tsx
📚 Learning: 2025-09-19T11:38:59.206Z
Learnt from: fairlighteth
Repo: cowprotocol/cowswap PR: 6232
File: apps/cowswap-frontend/src/modules/tokensList/pure/ChainsSelector/index.tsx:199-200
Timestamp: 2025-09-19T11:38:59.206Z
Learning: The makeBuildClickEvent function in apps/cowswap-frontend/src/modules/tokensList/pure/ChainsSelector/index.tsx takes five parameters: defaultChainId, contextLabel, mode, isSwapMode, and chainsCount. The chainsCount parameter is used to determine the CrossChain flag in analytics events.

Applied to files:

  • apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeChangeApproveAmountModal/TradeChangeApproveAmountModal.tsx
  • apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModal.tsx
📚 Learning: 2025-06-16T15:58:00.268Z
Learnt from: alfetopito
Repo: cowprotocol/cowswap PR: 5830
File: apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/index.tsx:1-2
Timestamp: 2025-06-16T15:58:00.268Z
Learning: JSX can be imported as a named export from React in modern React versions (React 17+). The import `import { JSX } from 'react'` is valid and does not cause compilation errors.

Applied to files:

  • apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveContainer/PartialApproveContainer.tsx
🧬 Code graph analysis (10)
apps/cowswap-frontend/src/modules/erc20Approve/containers/Erc20ApproveWidget/index.tsx (3)
apps/cowswap-frontend/src/modules/trade/hooks/useDerivedTradeState.ts (1)
  • useDerivedTradeState (7-9)
apps/cowswap-frontend/src/modules/erc20Approve/state/useSetUserApproveAmountModalState.ts (1)
  • useSetUserApproveAmountModalState (5-7)
libs/common-utils/src/isSellOrder.ts (1)
  • isSellOrder (3-5)
apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGetAmountToSignApprove.tsx (1)
apps/cowswap-frontend/src/modules/erc20Approve/hooks/useIsPartialApprovalModeSelected.ts (1)
  • useIsPartialApprovalModeSelected (5-7)
apps/cowswap-frontend/src/modules/account/containers/OrderPartialApprove/OrderPartialApprove.tsx (2)
apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveAmountModal/PartialApproveAmountModal.tsx (1)
  • PartialApproveAmountModal (15-28)
apps/cowswap-frontend/src/modules/account/containers/OrderPartialApprove/styled.ts (1)
  • OrderActionsWrapper (3-7)
apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveWithAffectedOrderList/TradeApproveWithAffectedOrderList.tsx (2)
apps/cowswap-frontend/src/modules/erc20Approve/hooks/useIsApprovalOrPermitRequired.ts (1)
  • useIsApprovalOrPermitRequired (31-64)
apps/cowswap-frontend/src/modules/erc20Approve/hooks/useIsPartialApprovalModeSelected.ts (1)
  • useIsPartialApprovalModeSelected (5-7)
apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeChangeApproveAmountModal/TradeChangeApproveAmountModal.tsx (3)
apps/cowswap-frontend/src/modules/erc20Approve/state/useSetUserApproveAmountModalState.ts (1)
  • useSetUserApproveAmountModalState (5-7)
apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGetPartialAmountToSignApprove.ts (1)
  • useGetPartialAmountToSignApprove (15-31)
apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModal.tsx (1)
  • ChangeApproveAmountModal (18-57)
apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveContainer/PartialApproveContainer.tsx (4)
apps/cowswap-frontend/src/modules/erc20Approve/hooks/useIsPartialApprovalModeSelected.ts (1)
  • useIsPartialApprovalModeSelected (5-7)
apps/cowswap-frontend/src/modules/erc20Approve/constants/maxApproveAmount.ts (1)
  • MAX_APPROVE_AMOUNT (3-3)
apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveAmountModal/PartialApproveAmountModal.tsx (1)
  • PartialApproveAmountModal (15-28)
apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveToggle/TradeApproveToggle.tsx (1)
  • TradeApproveToggle (13-25)
apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModal.tsx (1)
apps/cowswap-frontend/src/modules/erc20Approve/state/customApproveAmountInputState.ts (2)
  • useCustomApproveAmountInputState (32-34)
  • useUpdateOrResetCustomApproveAmountInputState (23-30)
apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveAmountModal/PartialApproveAmountModal.tsx (2)
apps/cowswap-frontend/src/modules/erc20Approve/state/partialApproveAmountModalState.ts (1)
  • useUpdatePartialApproveAmountModalState (21-23)
apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModal.tsx (1)
  • ChangeApproveAmountModal (18-57)
apps/cowswap-frontend/src/modules/erc20Approve/containers/ApprovalAmountInput/ApprovalAmountInput.tsx (1)
apps/cowswap-frontend/src/modules/erc20Approve/state/customApproveAmountInputState.ts (2)
  • useUpdateOrResetCustomApproveAmountInputState (23-30)
  • useCustomApproveAmountInputState (32-34)
apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModalPure.tsx (1)
apps/cowswap-frontend/src/modules/erc20Approve/containers/ApprovalAmountInput/ApprovalAmountInput.tsx (1)
  • ApprovalAmountInput (27-97)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Setup
  • GitHub Check: Cypress
🔇 Additional comments (13)
apps/cowswap-frontend/src/modules/erc20Approve/state/customApproveAmountInputState.ts (1)

2-2: Good practice: memoizing the reset function.

Wrapping the reset function with useCallback ensures referential stability for consumers of this hook, which aligns well with the PR's goal of stabilizing callbacks to support prop-driven approval flows.

Also applies to: 28-28

apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeChangeApproveAmountModal/TradeChangeApproveAmountModal.tsx (1)

3-18: LGTM!

The addition of amountToSwap prop correctly threads the maximum sell amount from the quote through to the modal for validation.

apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGetAmountToSignApprove.tsx (1)

9-44: LGTM!

Refactoring from atom-based to hook-based partial approval check improves encapsulation and aligns with the broader changes in this PR.

apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveContainer/PartialApproveContainer.tsx (1)

41-41: Verify prop values for PartialApproveAmountModal.

Both initialAmountToApprove and amountToSwap are set to amountToApprove. Based on the pattern in OrderPartialApprove.tsx (line 48), initialAmountToApprove should likely be partialAmountToApproveFinal (which includes user customization via amountSetByUser), while amountToSwap remains amountToApprove.

Apply this diff if the pattern should match OrderPartialApprove:

-    return <PartialApproveAmountModal initialAmountToApprove={amountToApprove} amountToSwap={amountToApprove} />
+    return <PartialApproveAmountModal initialAmountToApprove={partialAmountToApproveFinal} amountToSwap={amountToApprove} />
apps/cowswap-frontend/src/modules/account/containers/OrderPartialApprove/OrderPartialApprove.tsx (1)

47-49: LGTM!

The addition of amountToSwap={amountToApprove} correctly threads the swap amount through to the modal.

apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveWithAffectedOrderList/TradeApproveWithAffectedOrderList.tsx (1)

8-19: LGTM!

Removal of currentAllowance display and migration to hook-based partial approval checking aligns with PR objectives to fix the partial approval bug.

apps/cowswap-frontend/src/modules/erc20Approve/containers/PartialApproveAmountModal/PartialApproveAmountModal.tsx (1)

3-25: LGTM!

The addition of amountToSwap prop with a clear explanatory comment improves the API's clarity and enables proper validation in downstream components.

apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModal.tsx (1)

4-50: LGTM!

The addition of amountToSwap prop and adjustment to onBack behavior (removing amountSetByUser reset) correctly implements the intended flow where the custom amount is preserved when navigating back but cleared when confirming or resetting.

apps/cowswap-frontend/src/modules/erc20Approve/containers/ChangeApproveAmountModal/ChangeApproveAmountModalPure.tsx (2)

13-23: LGTM! Clear semantic improvements.

The interface changes improve clarity by distinguishing between the initial approve amount and the amount to swap. The added comments are helpful, and the new amountToSwap and onReset props enable the partial approval reset functionality described in the PR objectives.


46-51: Props correctly threaded to ApprovalAmountInput.

The prop renaming from initialAmount to initialApproveAmount is consistent with the interface changes in ApprovalAmountInput.tsx, and the new props amountToSwap and onReset are correctly passed through.

apps/cowswap-frontend/src/modules/erc20Approve/containers/ApprovalAmountInput/ApprovalAmountInput.tsx (3)

18-32: LGTM! Improved semantic clarity.

The prop renaming from initialAmount to initialApproveAmount and the addition of amountToSwap make the distinction between "amount to approve" and "amount to swap" much clearer. The added comments are helpful.


55-71: LGTM! Correct validation logic.

The validation now correctly checks if the entered amount is less than amountToSwap rather than initialAmount. This ensures users cannot approve less than they need to swap, which aligns with the partial approval fixes mentioned in the PR objectives. The edge case where amountToSwap is null/undefined is properly handled.


36-39: Add useEffect to reset custom approve amount when trade changes.

The custom approve amount state does not automatically reset when the trade changes. Currently, the fallback chain customAmountValueState.amount ?? initialApproveAmount ?? amountToSwap will use a persisted custom amount even after the user changes their trade (updating amountToSwap).

To fix this, add a useEffect in ChangeApproveAmountModal that monitors amountToSwap and calls resetCustomApproveAmountInput() when it changes:

useEffect(() => {
  resetCustomApproveAmountInput()
}, [amountToSwap, resetCustomApproveAmountInput])

Alternatively, close the modal automatically when the trade changes by including it in the resetAllScreens callback in TradeWidgetModals.tsx.

⛔ Skipped due to learnings
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 5859
File: apps/cowswap-frontend/src/modules/tradeQuote/hooks/useTradeQuotePolling.ts:76-82
Timestamp: 2025-06-23T07:03:50.760Z
Learning: In the useTradeQuotePolling hook, there are two useLayoutEffect hooks that work together: one resets the counter to 0 when the confirmation modal closes, and another automatically triggers pollQuote(false, true) whenever the counter reaches 0. This creates an intentional chain reaction for immediate quote updates.
Learnt from: fairlighteth
Repo: cowprotocol/cowswap PR: 6347
File: apps/cowswap-frontend/src/modules/trade/pure/TradeConfirmation/index.tsx:49-49
Timestamp: 2025-10-10T20:28:16.565Z
Learning: In apps/cowswap-frontend/src/modules/trade, TradeConfirmation follows a two-layer architecture: TradeConfirmationView (pure/stateless) in pure/TradeConfirmation/index.tsx renders the UI, while TradeConfirmation (container) in containers/TradeConfirmation/index.tsx wraps it to freeze props during pending trades (via useStableTradeConfirmationProps), wire in signing state (useSigningStep), and inject trade confirmation state (useTradeConfirmState). Consuming modules should import the container TradeConfirmation from 'modules/trade' to preserve this stateful behavior.
<!-- [add_learning]
When reviewing component refactoring in apps/cowswap-frontend/src/modules/trade, recognize the pattern where a pure view component (e.g., TradeConfirmationView) is separated from a stateful container (e.g., TradeConfirmation) that wraps it. The container adds runtime state management (prop stabilization, signing state, etc.) while the view remains testable and composable. Do not flag usages that import the container as outdated when the pure view is renamed or refactored.
Learnt from: limitofzero
Repo: cowprotocol/cowswap PR: 6351
File: apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts:87-121
Timestamp: 2025-10-13T19:41:31.440Z
Learning: In apps/cowswap-frontend/src/modules/erc20Approve, useApproveCallback returns Promise<TransactionResponse | undefined> and is distinct from useApproveCurrency, which can return Promise<TransactionReceipt | SafeMultisigTransactionResponse>. When reviewing approval flows, verify which hook is actually being used before flagging Safe wallet concerns.

Copy link
Contributor

@elena-zh elena-zh left a comment

Choose a reason for hiding this comment

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

Hey @limitofzero , thank you. I'm approving the PR.
However, I've been able to catch a weird issue here:

  1. Placed an order with a permittable token, approval amount >sell amount
  2. the order has been traded
  3. in a while, I specified an order with a sell amount > approved one --> approve button did not appear, I placed an unfillable order in the end.

This issue stopped to be reproducible in ~30 seconds, so, I assume, it might be related to allowances check that runs with a delay.

Copy link
Collaborator

@alfetopito alfetopito left a comment

Choose a reason for hiding this comment

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

Tested and it's working as described.

Except that the first time, it showed the approval again.
By accident I refreshed the page and it didn't show the approval anymore.

@elena-zh elena-zh requested a review from fairlighteth November 3, 2025 14:19
@alfetopito alfetopito disabled auto-merge November 3, 2025 14:20
@alfetopito alfetopito merged commit 73dbdbc into develop Nov 3, 2025
15 checks passed
@alfetopito alfetopito deleted the fix/update-allowance-earlier branch November 3, 2025 14:20
@github-actions github-actions bot locked and limited conversation to collaborators Nov 3, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants