Skip to content

Conversation

@limitofzero
Copy link
Contributor

@limitofzero limitofzero commented Dec 4, 2025

RWA Geo-blocking & User Consent Flow

First PR for RWA geo-block implementation.
Implements geo-blocking and consent verification for restricted tokens (Ondo Finance RWA tokens).

Changes

image
  • Restricted token list loading: Fetches token lists with restricted tokens (hardcoded for this PR - will address loading when CMS is ready)
  • Geo-detection: Checks user's country via API to determine if trading is allowed
  • Consent flow: Shows consent modal when geo is unavailable; stores consent per wallet + IPFS hash
  • Trade validation: Blocks trading with "Not available in your region" if user is in restricted country
  • AppData integration: Includes user consent metadata in order appData
image

Terms of Service

The consent references the Ondo Finance Terms of Service stored on IPFS:

Related PRs

  • SDK fix for duplicate consents: cowprotocol/cow-sdk#761 - Fixes deepmerge array concatenation issue in appData
  • Restricted token cache & import logic: cowprotocol/cowswap#6734 - Handles IndexDB cache for restricted token lists and importing restricted tokens flow

Configuration

Restricted countries can be configured via CMS:

Test Cases

Before testing - enable ff isRwaGeoblockEnabled

1. Geo-blocking behavior

Scenario Expected Result
User in restricted country Shows "Not available in your region" - cannot trade
User in allowed country Can trade normally without consent prompt
Geo API unavailable/unknown Shows consent modal before trading
Consent signed + geo unknown Can proceed with trade

2. Consent flow

  • Select a restricted token (e.g., OUSG, USDY)
  • If geo unavailable → consent modal appears
  • Accept consent → can proceed with trade
  • Decline consent → cannot trade

3. Consent persistence

  • Sign consent → refresh page → consent persists (no re-prompt)
  • Different wallet → requires new consent

4. AppData integration

  • If user signed consent and country is unknown, order should contain userConsents in appData

How to Test

Testing "Unknown Country" scenario

  1. Open browser DevTools → Network tab
  2. Block requests to the geo API endpoint (right-click → "Block request URL")
  3. Try to trade a restricted token
  4. Consent modal should appear

Testing "Restricted Country" scenario

  1. Use a VPN to connect from a restricted country (e.g., US for certain tokens)
  2. Try to trade a restricted token
  3. Should show "Not available in your region" message

Summary by CodeRabbit

  • New Features

    • RWA consent modal (token details, consent link, Confirm/Cancel) and modal flow integration into trade confirmation
    • Automatic country detection / geo-status that can restrict trades or require consent
    • Consent storage/management (confirm/reset) and propagation into app metadata and validation/trade flow
    • Restricted token lists auto-update, token-status hooks, and token identity helpers
  • Localization

    • Added US/EU/EEA, sanctions and region-specific consent/regulatory copy
  • Chores

    • Cow Protocol SDK version bump (patch)

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Dec 4, 2025

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

Project Deployment Review Updated (UTC)
cowfi Ready Ready Preview Dec 25, 2025 0:44am
explorer-dev Ready Ready Preview Dec 25, 2025 0:44am
swap-dev Ready Ready Preview Dec 25, 2025 0:44am
widget-configurator Ready Ready Preview Dec 25, 2025 0:44am
2 Skipped Deployments
Project Deployment Review Updated (UTC)
cosmos Ignored Ignored Dec 25, 2025 0:44am
sdk-tools Ignored Ignored Preview Dec 25, 2025 0:44am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 4, 2025

Walkthrough

Adds a complete RWA consent flow: types, Jotai storage atoms, geo lookup and restricted-token updater, hooks and modal (presentational + container), app-data consent propagation, trade validation gating, token identity helpers, CMS integration, and barrel exports.

Changes

Cohort / File(s) Summary
RWA Types & Cache
apps/cowswap-frontend/src/modules/rwa/types/rwaConsent.ts, apps/cowswap-frontend/src/modules/rwa/state/rwaConsentAtom.ts
New consent types, key builder, localStorage-backed rwaConsentCacheAtom, storeRwaConsentAtom, removeRwaConsentAtom, and getConsentFromCache.
RWA Modal State & Hooks
apps/cowswap-frontend/src/modules/rwa/state/rwaConsentModalStateAtom.ts, apps/cowswap-frontend/src/modules/rwa/hooks/useRwaConsentModalState.ts, apps/cowswap-frontend/src/modules/rwa/hooks/useRwaConsentStatus.ts, apps/cowswap-frontend/src/modules/rwa/hooks/useGeoCountry.ts, apps/cowswap-frontend/src/modules/rwa/hooks/useGeoStatus.ts
Modal state atom + updater and hooks to manage modal visibility, per-key consent status, and geo data fetching/exposure.
RWA Token Status & Integration
apps/cowswap-frontend/src/modules/rwa/hooks/useRwaTokenStatus.ts, apps/cowswap-frontend/src/modules/rwa/index.ts
New RwaTokenStatus enum, RwaTokenInfo/status hook, and barrel exports for RWA modules.
RWA UI & Container
apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/*, apps/cowswap-frontend/src/modules/rwa/containers/RwaConsentModalContainer/index.tsx, apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/styled.ts
Presentational modal component, styles, and container wiring that opens modal, persists consent, and triggers trade actions.
Restricted Tokens (libs/tokens)
libs/tokens/src/state/restrictedTokens/*, libs/tokens/src/hooks/tokens/useRestrictedToken.ts, libs/tokens/src/updaters/RestrictedTokensListUpdater/*, libs/tokens/src/index.ts
New restricted-token state (TokenId/getTokenId), lookup hooks (useRestrictedToken, useAnyRestrictedToken), updater to fetch CMS lists, and public exports.
CMS utils & types
libs/core/src/cms/types.ts, libs/core/src/cms/utils/getRestrictedTokenLists.ts, libs/core/src/cms/utils/index.ts
New CMS types and getRestrictedTokenLists utility used by the restricted-tokens updater.
Token identity utils
libs/common-utils/src/areTokensEqual.ts, libs/common-utils/src/index.ts
TokenId type, getTokenId, areTokensEqual helper and re-export.
AppData: consent propagation
apps/cowswap-frontend/src/modules/appData/hooks/useRwaConsentForAppData.ts, apps/cowswap-frontend/src/modules/appData/updater/AppDataInfoUpdater.ts, apps/cowswap-frontend/src/modules/appData/updater/AppDataUpdater.tsx, apps/cowswap-frontend/src/modules/appData/utils/buildAppData.ts
New useRwaConsentForAppData + UserConsentsMetadata; thread userConsent through app-data builders and include in generated metadata.
Trade validation & UI wiring
apps/cowswap-frontend/src/modules/tradeFormValidation/*, apps/cowswap-frontend/src/modules/swap/containers/TradeButtons/index.tsx, apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx
Adds TradeFormValidation.RestrictedForCountry, isRestrictedForCountry flag, injects geo restriction into validations, and gates confirm flow to open RWA modal when required.
App Updaters Mount
apps/cowswap-frontend/src/modules/application/containers/App/Updaters.tsx
Mounts RestrictedTokensListUpdater at startup.
Localization
apps/cowswap-frontend/src/locales/en-US.po
New/enhanced translation strings for RWA modal and regulatory disclaimers.
Deps & Misc edits
package.json, assorted formatting tweaks
Patch bump @cowprotocol/cow-sdk and many small formatting/whitespace changes across various files.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant TradeUI as Trade UI
    participant RwaHook as useRwaTokenStatus
    participant TokenStore as RestrictedTokens Atom
    participant Geo as Geo Atom / useGeoStatus
    participant Modal as RwaConsentModal
    participant Consent as useRwaConsentStatus
    participant Storage as localStorage
    participant AppData as buildAppData

    User->>TradeUI: Click Confirm
    TradeUI->>RwaHook: request token status (input/output)
    RwaHook->>TokenStore: lookup restricted token (consentHash, blockedCountries)
    RwaHook->>Geo: ensure country (fetch if needed)
    TokenStore-->>RwaHook: consentHash + blockedCountries
    Geo-->>RwaHook: country | loading

    alt Country is blocked
        RwaHook-->>TradeUI: Restricted
        TradeUI->>User: show "not available in your region"
    else Consent required and missing
        RwaHook-->>TradeUI: RequiredConsent
        TradeUI->>Modal: open(consentHash, token)
        Modal->>User: display terms
        User->>Modal: Confirm
        Modal->>Consent: confirmConsent(key)
        Consent->>Storage: persist acceptedAt
        Storage-->>Consent: stored
        Consent-->>Modal: confirmed
        Modal->>TradeUI: close
        TradeUI->>AppData: include userConsent metadata
        TradeUI->>User: proceed
    else Consent already signed
        RwaHook-->>TradeUI: ConsentIsSigned
        TradeUI->>AppData: include existing consent metadata
        TradeUI->>User: proceed
    else Allowed
        RwaHook-->>TradeUI: Allowed
        TradeUI->>User: proceed
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

Tokens

Suggested reviewers

  • fairlighteth
  • elena-zh

"🐇 I hopped through atoms, hooks, and state,
I fetched each country and mapped each fate,
I opened a modal and stored a kindly 'I Confirm',
Now trades pause or pass where rules affirm —
A tiny rabbit patch to keep flows straight."

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: implementing consent logic for restricted tokens, which aligns with the geo-blocking and user consent flow feature introduced in this PR.
Description check ✅ Passed The PR description provides comprehensive context including summary, changes overview, related PRs, configuration, and detailed test cases. However, it does not follow the required template structure with explicit 'Summary', 'To Test', and 'Background' sections.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/rwa-geoblock

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.

@limitofzero
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 4, 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.

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: 4

🧹 Nitpick comments (2)
apps/cowswap-frontend/src/modules/rwa/types/rwaConsent.ts (1)

15-17: Consider validating or escaping key components to prevent collisions.

The storage key construction uses colons as separators. If any of wallet, issuer, or tosVersion contain colons, it could lead to key collisions (e.g., wallet="a:b", issuer="c" would collide with wallet="a", issuer="b:c").

While unlikely in practice, consider either:

  • Validating inputs to reject/escape special characters
  • Using a more robust serialization (e.g., JSON.stringify([wallet, issuer, tosVersion]))
apps/cowswap-frontend/src/modules/rwa/hooks/useRwaConsentStatus.ts (1)

15-20: Consider key stability for useMemo dependency.

The statusAtom is recreated whenever the key object reference changes (line 17), even if its values are identical. While callers should use useMemo for the key, you could add resilience here with a serialized dependency.

 export function useRwaConsentStatus(key: RwaConsentKey): UseRwaConsentStatusReturn {
   const consentAtom = getRwaConsentAtom(key)
-  const statusAtom = useMemo(() => createRwaConsentStatusAtom(key), [key])
+  const statusAtom = useMemo(
+    () => createRwaConsentStatusAtom(key),
+    [key.wallet, key.issuer, key.tosVersion]
+  )

This ensures the atom is only recreated when the actual values change, not just the object reference.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16788e6 and 0e41f57.

📒 Files selected for processing (7)
  • apps/cowswap-frontend/src/modules/rwa/components/RwaSelfCertificationModal/RwaSelfCertificationModal.tsx (1 hunks)
  • apps/cowswap-frontend/src/modules/rwa/components/RwaSelfCertificationModal/index.ts (1 hunks)
  • apps/cowswap-frontend/src/modules/rwa/hooks/useRwaConsentStatus.ts (1 hunks)
  • apps/cowswap-frontend/src/modules/rwa/hooks/useRwaSelfCertification.tsx (1 hunks)
  • apps/cowswap-frontend/src/modules/rwa/index.ts (1 hunks)
  • apps/cowswap-frontend/src/modules/rwa/state/rwaConsentAtom.ts (1 hunks)
  • apps/cowswap-frontend/src/modules/rwa/types/rwaConsent.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
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...
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: alfetopito
Repo: cowprotocol/cowswap PR: 6234
File: libs/tokens/src/index.ts:1-4
Timestamp: 2025-09-11T08:25:51.460Z
Learning: In the cowprotocol/cowswap project, there is currently no SSR (Server-Side Rendering) support, so localStorage access at module import time does not cause SSR-related issues.
📚 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/rwa/components/RwaSelfCertificationModal/index.ts
  • apps/cowswap-frontend/src/modules/rwa/components/RwaSelfCertificationModal/RwaSelfCertificationModal.tsx
  • apps/cowswap-frontend/src/modules/rwa/state/rwaConsentAtom.ts
  • apps/cowswap-frontend/src/modules/rwa/index.ts
  • apps/cowswap-frontend/src/modules/rwa/hooks/useRwaConsentStatus.ts
  • apps/cowswap-frontend/src/modules/rwa/hooks/useRwaSelfCertification.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/rwa/state/rwaConsentAtom.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/rwa/state/rwaConsentAtom.ts
📚 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/rwa/hooks/useRwaSelfCertification.tsx
🧬 Code graph analysis (4)
apps/cowswap-frontend/src/modules/rwa/components/RwaSelfCertificationModal/RwaSelfCertificationModal.tsx (3)
libs/types/src/common.ts (1)
  • Command (3-3)
apps/cowswap-frontend/src/common/pure/Modal/index.tsx (1)
  • Modal (35-105)
apps/cowswap-frontend/src/common/pure/ConfirmationModal/ConfirmationModalHeader.tsx (1)
  • ConfirmationModalHeader (46-53)
apps/cowswap-frontend/src/modules/rwa/state/rwaConsentAtom.ts (3)
apps/cowswap-frontend/src/modules/rwa/types/rwaConsent.ts (3)
  • RwaConsentRecord (3-7)
  • RwaConsentKey (9-13)
  • getRwaConsentStorageKey (15-17)
apps/cowswap-frontend/public/emergency.js (1)
  • key (22-22)
libs/core/src/jotaiStore.ts (1)
  • getJotaiMergerStorage (44-57)
apps/cowswap-frontend/src/modules/rwa/hooks/useRwaConsentStatus.ts (2)
apps/cowswap-frontend/src/modules/rwa/types/rwaConsent.ts (2)
  • GeoMode (1-1)
  • RwaConsentKey (9-13)
apps/cowswap-frontend/src/modules/rwa/state/rwaConsentAtom.ts (2)
  • getRwaConsentAtom (23-31)
  • createRwaConsentStatusAtom (34-41)
apps/cowswap-frontend/src/modules/rwa/hooks/useRwaSelfCertification.tsx (4)
apps/cowswap-frontend/src/modules/rwa/types/rwaConsent.ts (2)
  • GeoMode (1-1)
  • RwaConsentKey (9-13)
libs/wallet/src/api/hooks.ts (1)
  • useWalletInfo (24-26)
apps/cowswap-frontend/src/modules/rwa/hooks/useRwaConsentStatus.ts (1)
  • useRwaConsentStatus (15-49)
apps/cowswap-frontend/src/modules/rwa/components/RwaSelfCertificationModal/RwaSelfCertificationModal.tsx (1)
  • RwaSelfCertificationModal (45-94)
🔇 Additional comments (3)
apps/cowswap-frontend/src/modules/rwa/components/RwaSelfCertificationModal/index.ts (1)

1-3: LGTM!

Clean barrel export following the project's module organization pattern.

apps/cowswap-frontend/src/modules/rwa/index.ts (1)

1-6: LGTM!

Clean module barrel export organizing all RWA consent functionality.

apps/cowswap-frontend/src/modules/rwa/hooks/useRwaConsentStatus.ts (1)

22-31: LGTM!

The confirmConsent callback correctly updates the consent record with the provided geoMode and timestamp.

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: 0

♻️ Duplicate comments (1)
apps/cowswap-frontend/src/locales/en-US.po (1)

1532-1534: Align “By clicking Confirm…” text with the “I Confirm” button label

The explanatory sentence still references a "Confirm" CTA, while the actual button label is "I Confirm". For legal clarity and UX consistency, consider either:

  • Updating the sentence to By clicking "I Confirm", you expressly represent and warrant that you are NOT:, or
  • Renaming the button to “Confirm” so it matches the copy.

This was already raised in a previous review and remains unresolved, so worth tightening before shipping.

Also applies to: 5964-5966

🧹 Nitpick comments (1)
apps/cowswap-frontend/src/locales/en-US.po (1)

238-240: Double‑check scope and intent of RWA disqualification bullets

The disqualifying categories currently include:

  • “A resident of any jurisdiction where trading securities or cryptographic tokens is regulated or prohibited by applicable laws.”
  • “A U.S. Person or resident of the United States.”
  • “A resident of the EU or EEA.”
  • “A resident of any country subject to international sanctions (e.g., OFAC, UN lists).”
  • Plus the follow‑up lines about selecting Cancel and being solely responsible for complying with local laws.

From a purely textual/readability standpoint these are consistent and clearly phrased. However, “regulated or prohibited” is extremely broad (almost all jurisdictions regulate securities / tokens), so in practice this could be read as excluding nearly everyone.

Recommend confirming with product/legal that this exact scope and phrasing is intentional for this consent flow, and adjusting the language (e.g. narrowing to “prohibited” or “where such trading is not legally permitted for you”) if that better reflects the intended restriction.

Also applies to: 544-547, 585-588, 1893-1896, 2009-2012, 3615-3618

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4fd7b24 and 007410f.

📒 Files selected for processing (1)
  • apps/cowswap-frontend/src/locales/en-US.po
🧰 Additional context used
🧠 Learnings (5)
📚 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/locales/en-US.po
📚 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/locales/en-US.po
📚 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/locales/en-US.po
📚 Learning: 2025-07-24T16:43:47.639Z
Learnt from: cowdan
Repo: cowprotocol/cowswap PR: 6009
File: apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/HighFeeWarning/highFeeWarningHelpers.ts:18-20
Timestamp: 2025-07-24T16:43:47.639Z
Learning: In apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/HighFeeWarning/highFeeWarningHelpers.ts, the formatFeePercentage function uses ROUND_DOWN with toSignificant(2) for "at least X%" messaging. This ensures the displayed percentage is never higher than the actual fee, making the "at least" phrasing accurate. For example, if the actual fee is 25.4%, displaying "at least 25%" is correct, but "at least 26%" would be misleading.

Applied to files:

  • apps/cowswap-frontend/src/locales/en-US.po
📚 Learning: 2025-05-27T12:20:54.659Z
Learnt from: alfetopito
Repo: cowprotocol/cowswap PR: 5762
File: apps/cowswap-frontend/src/legacy/state/orders/utils.ts:499-503
Timestamp: 2025-05-27T12:20:54.659Z
Learning: In the CowSwap frontend, when displaying volume fees in the UI (like in ReceiptModal), zero fees (0 bps) should be treated as "free" and hidden from display. Only non-zero fees should show the "Total fee" line. This provides a cleaner UX by not cluttering the interface with "0.00%" fee displays.

Applied to files:

  • apps/cowswap-frontend/src/locales/en-US.po
⏰ 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: Cypress
  • GitHub Check: Setup
🔇 Additional comments (2)
apps/cowswap-frontend/src/locales/en-US.po (2)

1055-1058: Geo‑undetermined and region‑blocked messages look coherent

The new copy:

  • Explains why additional confirmation is needed when location cannot be determined (“e.g., due to VPN or privacy settings”) and states that access is limited to specific regions.
  • Uses a clear, neutral hard‑block message (“This token is not available in your region”).
  • Pairs well with the “Additional confirmation required for this token” header.

Wording is concise, user‑understandable, and consistent with a geo‑gated RWA flow.

Also applies to: 1359-1362, 1367-1370


4055-4058: Network costs / fees wording is internally consistent

The terminology updates:

  • Labeling the row as “Network costs” in the amount breakdown,
  • Explaining that “CoW Protocol covers the fees and costs by executing your order at a slightly better price than your limit price,” and
  • Using “Network fees and costs” as the explanatory label in the receipt,

are consistent with each other and with the rest of the UI language around settlement costs vs protocol/partner fees. No issues from a copy or UX perspective.

Also applies to: 3588-3590, 5314-5316

@shoom3301 shoom3301 merged commit 14686d1 into develop Dec 25, 2025
17 checks passed
@shoom3301 shoom3301 deleted the feat/rwa-geoblock branch December 25, 2025 12:48
@github-actions github-actions bot locked and limited conversation to collaborators Dec 25, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants