refactor(swap): bundle optimization#6775
Conversation
…-utils methods and hardcode used consts added eslint restrict rules
dynamic import @safe-global/api-kit
@ethereumjs/util (esm) @walletconnect/ethereum-provider @walletconnect/types @walletconnect/utils
…tion and lottie-react
|
@crutch12 is attempting to deploy a commit to the cow Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughMade lint-rule migrations, migrated Safe/permit integrations to async/dynamic imports, centralized 1inch permit constants, introduced lazy loading for Lottie/framer-motion, adjusted nonce/transaction-hash types to string/BigInt flows, added bundle-stats and chunk naming helpers, and bumped/updated related dependencies. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant useSafeApiKit
participant gnosisSafe
participant SafeApiKit
rect rgba(200,150,255,0.5)
Note over Client,SafeApiKit: Old Flow (synchronous provider-based)
Client->>useSafeApiKit: mount(chainId, provider)
useSafeApiKit->>gnosisSafe: getSafeTransaction(chainId, hash, provider)
gnosisSafe->>SafeApiKit: instantiate SafeApiKit with EthAdapter (sync import)
SafeApiKit-->>gnosisSafe: instance
gnosisSafe-->>useSafeApiKit: transaction data
useSafeApiKit-->>Client: update state
end
rect rgba(100,200,100,0.5)
Note over Client,SafeApiKit: New Flow (async dynamic import)
Client->>useSafeApiKit: mount(chainId)
useSafeApiKit->>gnosisSafe: getSafeTransaction(chainId, hash)
gnosisSafe->>gnosisSafe: await _getClientOrThrow(chainId)
gnosisSafe->>gnosisSafe: await createSafeApiKitInstance(chainId) (dynamic import)
gnosisSafe->>SafeApiKit: dynamic import + new SafeApiKit(txServiceUrl, chainId)
SafeApiKit-->>gnosisSafe: instance
gnosisSafe-->>useSafeApiKit: Promise<transaction data>
useSafeApiKit-->>Client: update state
end
sequenceDiagram
participant PermitHook
participant getPermitUtilsInstance
participant Cache
participant Eip2612PermitUtils
rect rgba(200,150,255,0.5)
Note over PermitHook,Eip2612PermitUtils: Old Flow (sync)
PermitHook->>getPermitUtilsInstance: call(chainId, provider, account)
getPermitUtilsInstance->>Cache: check cache
alt hit
Cache-->>getPermitUtilsInstance: Eip2612PermitUtils
else miss
getPermitUtilsInstance->>Eip2612PermitUtils: new Eip2612PermitUtils(...)
Eip2612PermitUtils-->>getPermitUtilsInstance: instance
getPermitUtilsInstance->>Cache: store instance
end
getPermitUtilsInstance-->>PermitHook: Eip2612PermitUtils
PermitHook->>Eip2612PermitUtils: getTokenNonce(...)
Eip2612PermitUtils-->>PermitHook: nonce
end
rect rgba(100,200,100,0.5)
Note over PermitHook,Eip2612PermitUtils: New Flow (async dynamic import)
PermitHook->>getPermitUtilsInstance: await call(chainId, provider, account)
getPermitUtilsInstance->>Cache: check cache
alt hit
Cache-->>getPermitUtilsInstance: Promise<Eip2612PermitUtils> | instance
else miss
getPermitUtilsInstance->>getPermitUtilsInstance: dynamic import('./imports/1inchPermitUtils')
getPermitUtilsInstance->>Eip2612PermitUtils: new Eip2612PermitUtils(...)
Eip2612PermitUtils-->>getPermitUtilsInstance: instance
getPermitUtilsInstance->>Cache: store instance
end
getPermitUtilsInstance-->>PermitHook: Promise<Eip2612PermitUtils>
PermitHook->>Eip2612PermitUtils: await getTokenNonce(...)
Eip2612PermitUtils-->>PermitHook: nonce
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
| } | ||
|
|
||
| export function getSafeTransaction( | ||
| export async function getSafeTransaction( |
There was a problem hiding this comment.
new versions of SafeApiKit don't requre Web3Provider
There was a problem hiding this comment.
Actionable comments posted: 7
♻️ Duplicate comments (7)
apps/cowswap-frontend/src/common/hooks/useGetSurplusFiatValue.ts (1)
1-1: Consistent lint rule migration.Same pattern as other files in this PR—correctly migrated to
@typescript-eslint/no-restricted-imports.apps/cowswap-frontend/src/common/containers/OrderHooksDetails/HookItem/index.tsx (1)
1-1: Consistent lint rule migration.apps/cowswap-frontend/src/common/hooks/useSwapResultsContext.ts (1)
1-1: Consistent lint rule migration.apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/types.ts (1)
1-1: Consistent lint rule migration.apps/cowswap-frontend/src/common/pure/ReceiveAmount/index.tsx (1)
1-1: Consistent lint rule migration.apps/cowswap-frontend/src/common/hooks/useRateInfoParams.ts (1)
1-1: Consistent lint rule migration.apps/cowswap-frontend/src/common/updaters/SentryUpdater.ts (1)
1-1: Consistent lint rule migration.
🧹 Nitpick comments (14)
apps/cowswap-frontend/src/lib/i18n.tsx (1)
59-62: Consider prioritizing this TODO to eliminate the initial null render.This TODO correctly identifies a UX issue where I18nProvider may render null during the initial render. Combined with the potential guard logic issue on lines 54-57, this could result in a flash of missing content for users.
Possible solutions:
- Pre-load the default locale messages before the first render (as suggested in the TODO).
- Ensure the synchronous guard on line 54 works correctly to activate the default locale immediately.
- Add a loading state/skeleton instead of rendering null.
apps/cowswap-frontend/src/modules/ordersTable/hooks/useNoOrdersAnimation.ts (1)
5-5: Consider using type-only import.
LottieComponentPropsis only used in type positions (line 17, 18). Usingimport typewould be more explicit and could help with tree-shaking:-import { LottieComponentProps } from 'lottie-react' +import type { LottieComponentProps } from 'lottie-react'However, if this change was intentional due to module resolution issues with
lottie-react, please disregard.apps/cowswap-frontend/src/common/updaters/orders/PendingOrdersUpdater.ts (1)
91-95: BigInt comparison logic is correct but guard differs from similar code.The logic correctly identifies replaced Safe transactions. Note that in
checkSafeTransaction.ts(line 26), the guard usestypeof safeNonce === 'string', while here it uses a truthy checksafeNonce &&.If
safeNoncecould be a number (fromGnosisSafeInfo), the BigInt conversion will still work correctly. However, consider aligning the guard style for consistency:- const isOrderTxReplaced = !!( - safeNonce && - BigInt(safeTransaction.nonce) < BigInt(safeNonce) && - !safeTransaction.isExecuted - ) + const isOrderTxReplaced = !!( + typeof safeNonce !== 'undefined' && + BigInt(safeTransaction.nonce) < BigInt(safeNonce) && + !safeTransaction.isExecuted + )libs/wallet/src/web3-react/connectors/TrezorConnector/getAccountsList.ts (1)
81-82: UseBuffer.from()instead of deprecatednew Buffer()constructor.The
Bufferconstructor with string arguments is deprecated and will show warnings. Consider updating these lines while making changes to this file:🔎 Proposed fix
- hdKey.publicKey = new Buffer(payload.publicKey, 'hex') - hdKey.chainCode = new Buffer(payload.chainCode, 'hex') + hdKey.publicKey = Buffer.from(payload.publicKey, 'hex') + hdKey.chainCode = Buffer.from(payload.chainCode, 'hex')libs/permit-utils/src/consts/1inchPermitUtils.ts (1)
1-68: LGTM! Well-documented rationale for hardcoding these constants.The approach of extracting stable constants from an archived library is sensible for bundle optimization. The permit selectors and typehash are cryptographic constants tied to EIP-2612 specifications and won't change.
Consider adding
as constto the ABI array for stricter typing if consumers need literal types:-export const DAI_EIP_2612_PERMIT_ABI = [ +export const DAI_EIP_2612_PERMIT_ABI = [ { // ... }, -] +] as consteslint.config.js (1)
149-155: Clarify the error message for the dynamic import restriction.The
no-restricted-syntaxrule blocks dynamic imports (import(...)) from@1inch/permit-signed-approvals-utils, but the message says "Please import dynamically from @cowprotocol/permit-utils". This could be confusing since you're blocking dynamic imports, not encouraging them.Consider rewording to clarify that developers should use the
@cowprotocol/permit-utilswrapper instead:🔎 Suggested fix
'no-restricted-syntax': [ 'error', { selector: 'ImportExpression[source.value="@1inch/permit-signed-approvals-utils"]', - message: 'Please import dynamically from @cowprotocol/permit-utils', + message: 'Please use @cowprotocol/permit-utils instead, which provides optimized dynamic imports', }, ],apps/cowswap-frontend/src/modules/orderProgressBar/pure/steps/FinishedStep.tsx (1)
40-47: Consider a loading skeleton fallback instead of null.The
nullfallback means users see nothing while the Lottie animation loads. For a better UX, consider a lightweight placeholder (e.g., a static checkmark icon or a small spinner) to avoid layout shift.apps/cowswap-frontend/src/modules/orderProgressBar/pure/StepComponent.tsx (1)
42-50: Consider a fallback for the Suspense boundary.The
nullfallback means users see nothing while the cancellation animation loads. Since this is a cancellation state, consider showing a simple static icon (e.g., an "X" or spinner) to provide immediate visual feedback during the lazy load.libs/permit-utils/src/imports/1inchPermitUtils.ts (1)
1-10: LGTM! Good selective re-export pattern for bundle optimization.The documentation clearly explains the rationale (642kb → 256kb reduction), and the ESLint disable is appropriate since this is the designated entry point for the dynamic import.
Minor typo in line 4: "dymaic" should be "dynamic".
🔎 Optional fix for typo
- * It uses esm, but dymaic import breaks tree shaking, so we re-export here only used variables (642kb -> 256kb). + * It uses esm, but dynamic import breaks tree shaking, so we re-export here only used variables (642kb -> 256kb).apps/cowswap-frontend/src/modules/orderProgressBar/pure/TopSections.tsx (1)
52-58: Consider loading states for better UX.Both components return
nullwhile the Lottie assets are loading. This could cause layout shifts or brief empty states in the UI. Consider whether a skeleton or placeholder would provide a smoother user experience, especially on slower connections.Also applies to: 92-98
tools/formatChunkFileName.ts (1)
8-17: Consider edge case where derived name becomes empty.If the path after the key consists only of segments like
index,dist,node_modules, orbrowser, thenamevariable could become an empty string (or just-), resulting in filenames likestatic/page--[hash].js.🔎 Proposed fix to handle empty name
const name = splitted[splitted.length - 1] .replace(/\/(index|dist|node_modules|browser)/g, '') .replace(/\.(tsx?|jsx?|mjs|mts|cjs)$/, '') .replace(/\//g, '-') + .replace(/^-+|-+$/g, '') // trim leading/trailing hyphens + if (!name) return undefined // fallback to default naming + return chunkGroups[key].replace(/\[name\]/g, name)libs/permit-utils/src/lib/getPermitUtilsInstance.ts (1)
17-51: Potential race condition during concurrent initial calls.If multiple callers invoke
getPermitUtilsInstancesimultaneously before the cache is populated, each will proceed to create a new instance (due to theawait import()), potentially resulting in multiple instances being created and only the last one being cached. This is a minor concern since the instances are functionally equivalent, but it wastes resources.🔎 Optional fix using a pending promise cache
+const PENDING_CACHE = new Map<string, Promise<Eip2612PermitUtils>>() + export async function getPermitUtilsInstance( chainId: number, provider: JsonRpcProvider, account?: string | undefined, ): Promise<Eip2612PermitUtils> { const chainCache = CHAIN_UTILS_CACHE.get(chainId) if (!account && chainCache) { return chainCache } const providerCacheKey = `${chainId}-${account}` const providerCache = PROVIDER_UTILS_CACHE.get(providerCacheKey) if (providerCache) { return providerCache } + const cacheKey = account ? providerCacheKey : `chain-${chainId}` + const pending = PENDING_CACHE.get(cacheKey) + if (pending) return pending + + const promise = (async () => { const web3ProviderConnector = new PermitProviderConnector(provider, account ? undefined : PERMIT_SIGNER) const Eip2612PermitUtilsClass = await import('../imports/1inchPermitUtils').then((r) => r.Eip2612PermitUtils) - const eip2612PermitUtils = new Eip2612PermitUtilsClass(web3ProviderConnector, { enabledCheckSalt: true }) + return new Eip2612PermitUtilsClass(web3ProviderConnector, { enabledCheckSalt: true }) + })() + + PENDING_CACHE.set(cacheKey, promise) + const eip2612PermitUtils = await promise + PENDING_CACHE.delete(cacheKey)libs/core/src/gnosisSafe/index.ts (1)
24-37: Same race condition concern as in permit utils.Similar to
getPermitUtilsInstance, concurrent calls to_getClientbefore the cache is populated could result in multipleSafeApiKitinstances being created. Given this is a heavier module with network-related setup, consider adding a pending promise cache.🔎 Optional fix using pending promise pattern
+const PENDING_CLIENTS = new Map<number, Promise<SafeApiKitType | null>>() + async function _getClient(chainId: number): Promise<SafeApiKitType | null> { const cachedClient = SAFE_TRANSACTION_SERVICE_CACHE[chainId] if (cachedClient !== undefined) { return cachedClient } + const pending = PENDING_CLIENTS.get(chainId) + if (pending) return pending + + const promise = createSafeApiKitInstance(chainId) + PENDING_CLIENTS.set(chainId, promise) + - const client = await createSafeApiKitInstance(chainId) + const client = await promise + PENDING_CLIENTS.delete(chainId) // Add client to cache (or null if unknown network) SAFE_TRANSACTION_SERVICE_CACHE[chainId] = client return client }apps/cowswap-frontend/vite.config.mts (1)
185-185: Update or remove the outdated comment about @1inch.The comment
// was used by @1inchis misleading—theweb3package is actively used in the codebase (imported in explorer utilities), and this manual chunk configuration helps ensure it bundles correctly. Either remove the comment entirely or clarify its actual purpose if there's a specific reason for this chunking strategy.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (92)
.gitignoreapps/cowswap-frontend/src/common/containers/CoWAmmBanner/index.tsxapps/cowswap-frontend/src/common/containers/CoWAmmBanner/types.tsapps/cowswap-frontend/src/common/containers/OrderHooksDetails/HookItem/index.tsxapps/cowswap-frontend/src/common/containers/OrderHooksDetails/index.tsxapps/cowswap-frontend/src/common/hooks/useCancelOrder/onChainCancellation.tsapps/cowswap-frontend/src/common/hooks/useCancelOrder/useGetOnChainCancellation.tsapps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.tsapps/cowswap-frontend/src/common/hooks/useConvertUsdToTokenValue.tsapps/cowswap-frontend/src/common/hooks/useEnhancedActivityDerivedState.tsapps/cowswap-frontend/src/common/hooks/useGetMarketDimension.tsapps/cowswap-frontend/src/common/hooks/useGetSurplusFiatValue.tsapps/cowswap-frontend/src/common/hooks/useNavigate.tsapps/cowswap-frontend/src/common/hooks/useOnSelectNetwork.tsxapps/cowswap-frontend/src/common/hooks/useRateInfoParams.tsapps/cowswap-frontend/src/common/hooks/useSafeApiKit.tsapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeContext.tsapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeOverview.tsapps/cowswap-frontend/src/common/hooks/useSwapResultsContext.tsapps/cowswap-frontend/src/common/pure/CoWAmmBannerContent/index.tsxapps/cowswap-frontend/src/common/pure/ConfirmationPendingContent/ConfirmationPendingContentShell.tsxapps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsxapps/cowswap-frontend/src/common/pure/CurrencyInputPanel/types.tsapps/cowswap-frontend/src/common/pure/ExecutionPrice/hooks/useExecutionPriceFiat.tsapps/cowswap-frontend/src/common/pure/ReceiveAmount/index.tsxapps/cowswap-frontend/src/common/pure/ReceiveAmountInfo/index.tsxapps/cowswap-frontend/src/common/types.tsapps/cowswap-frontend/src/common/updaters/SentryUpdater.tsapps/cowswap-frontend/src/common/updaters/WidgetTokensUpdater.tsxapps/cowswap-frontend/src/common/updaters/orders/CancelledOrdersUpdater.tsapps/cowswap-frontend/src/common/updaters/orders/OrdersFromApiUpdater.tsapps/cowswap-frontend/src/common/updaters/orders/PendingOrdersUpdater.tsapps/cowswap-frontend/src/common/updaters/orders/SpotPricesUpdater.tsapps/cowswap-frontend/src/common/updaters/orders/UnfillableOrdersUpdater/hooks/useUpdateIsUnfillableFlag.tsapps/cowswap-frontend/src/common/updaters/orders/UnfillableOrdersUpdater/updaters/UnfillableOrderUpdater.tsapps/cowswap-frontend/src/common/utils/doesOrderHavePermit.tsapps/cowswap-frontend/src/legacy/hooks/useGetSafeTxInfo.tsapps/cowswap-frontend/src/legacy/state/enhancedTransactions/actions.tsapps/cowswap-frontend/src/legacy/state/enhancedTransactions/reducer.tsapps/cowswap-frontend/src/legacy/state/orders/actions.tsapps/cowswap-frontend/src/lib/i18n.tsxapps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveButton/TradeApproveButton.tsxapps/cowswap-frontend/src/modules/erc20Approve/hooks/useApproveAndSwap.tsapps/cowswap-frontend/src/modules/erc20Approve/hooks/useApproveCurrency.tsapps/cowswap-frontend/src/modules/erc20Approve/utils/getIsTradeApproveResult.tsapps/cowswap-frontend/src/modules/limitOrders/services/safeBundleFlow/index.tsapps/cowswap-frontend/src/modules/onchainTransactions/updaters/FinalizeTxUpdater/services/checkSafeTransaction.tsapps/cowswap-frontend/src/modules/orderProgressBar/pure/LottieContainer.tsxapps/cowswap-frontend/src/modules/orderProgressBar/pure/RenderProgressTopSection.tsxapps/cowswap-frontend/src/modules/orderProgressBar/pure/StepComponent.tsxapps/cowswap-frontend/src/modules/orderProgressBar/pure/TopSections.tsxapps/cowswap-frontend/src/modules/orderProgressBar/pure/steps/FinishedStep.tsxapps/cowswap-frontend/src/modules/ordersTable/hooks/useDoesOrderHaveValidPermit.test.tsapps/cowswap-frontend/src/modules/ordersTable/hooks/useNoOrdersAnimation.tsapps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/NoOrdersContent.tsxapps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/fields/SafeTxFields.tsxapps/cowswap-frontend/src/modules/ordersTable/utils/checkPermitNonceAndAmount.tsapps/cowswap-frontend/src/modules/ordersTable/utils/extractPermitData.tsapps/cowswap-frontend/src/modules/permit/hooks/useGeneratePermitHook.tsapps/cowswap-frontend/src/modules/permit/hooks/useGetCachedPermit.tsapps/cowswap-frontend/src/modules/tradeFlow/services/safeBundleFlow/safeBundleApprovalFlow.tsapps/cowswap-frontend/src/modules/tradeFlow/services/safeBundleFlow/safeBundleEthFlow.tsapps/cowswap-frontend/src/modules/twap/services/cancelTwapOrderTxs.tsapps/cowswap-frontend/src/modules/twap/services/createTwapOrderTxs.tsapps/cowswap-frontend/src/modules/twap/services/extensibleFallbackSetupTxs.tsapps/cowswap-frontend/src/modules/twap/services/fetchTwapOrdersFromSafe.tsapps/cowswap-frontend/src/modules/twap/updaters/TwapOrdersUpdater.tsxapps/cowswap-frontend/src/modules/zeroApproval/hooks/useZeroApprove.tsapps/cowswap-frontend/src/utils/orderUtils/getOrderPermitAmount.test.tsapps/cowswap-frontend/src/utils/orderUtils/isPermitValidForOrder.tsapps/cowswap-frontend/vite.config.mtsapps/explorer/src/storybook/decorators.tsxapps/widget-configurator/src/app/embedDialog/index.tsxeslint.config.jslibs/core/src/gnosisSafe/index.tslibs/permit-utils/README.mdlibs/permit-utils/src/consts/1inchPermitUtils.tslibs/permit-utils/src/imports/1inchPermitUtils.tslibs/permit-utils/src/index.tslibs/permit-utils/src/lib/checkIsCallDataAValidPermit.tslibs/permit-utils/src/lib/getPermitUtilsInstance.tslibs/permit-utils/src/lib/getTokenPermitInfo.tslibs/permit-utils/src/utils/PermitProviderConnector.tslibs/permit-utils/src/utils/buildPermitCallData.tslibs/wallet/src/api/hooks/useSendBatchTransactions.tslibs/wallet/src/api/types.tslibs/wallet/src/web3-react/connectors/TrezorConnector/getAccountsList.tslibs/wallet/src/web3-react/connectors/TrezorConnector/index.tslibs/wallet/src/web3-react/hooks/useSafeAppsSdk.tslibs/wallet/src/web3-react/updater.tspackage.jsontools/formatChunkFileName.ts
💤 Files with no reviewable changes (1)
- .gitignore
🧰 Additional context used
🧠 Learnings (21)
📓 Common learnings
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-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/legacy/state/orders/actions.tsapps/cowswap-frontend/src/modules/twap/services/fetchTwapOrdersFromSafe.tsapps/cowswap-frontend/src/modules/limitOrders/services/safeBundleFlow/index.tsapps/cowswap-frontend/src/modules/erc20Approve/hooks/useApproveAndSwap.tsapps/cowswap-frontend/src/modules/twap/services/cancelTwapOrderTxs.tsapps/cowswap-frontend/src/common/hooks/useGetSurplusFiatValue.tsapps/cowswap-frontend/src/modules/onchainTransactions/updaters/FinalizeTxUpdater/services/checkSafeTransaction.tsapps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveButton/TradeApproveButton.tsxapps/cowswap-frontend/src/legacy/state/enhancedTransactions/actions.tsapps/cowswap-frontend/src/modules/tradeFlow/services/safeBundleFlow/safeBundleApprovalFlow.tsapps/cowswap-frontend/src/modules/ordersTable/utils/checkPermitNonceAndAmount.tsapps/cowswap-frontend/src/modules/ordersTable/utils/extractPermitData.tsapps/cowswap-frontend/src/legacy/hooks/useGetSafeTxInfo.tsapps/cowswap-frontend/src/modules/permit/hooks/useGetCachedPermit.tsapps/cowswap-frontend/src/modules/twap/services/extensibleFallbackSetupTxs.tslibs/permit-utils/src/lib/checkIsCallDataAValidPermit.tslibs/wallet/src/api/hooks/useSendBatchTransactions.tsapps/cowswap-frontend/src/common/hooks/useConvertUsdToTokenValue.tsapps/cowswap-frontend/src/modules/ordersTable/hooks/useDoesOrderHaveValidPermit.test.tslibs/wallet/src/web3-react/hooks/useSafeAppsSdk.tsapps/cowswap-frontend/src/modules/erc20Approve/hooks/useApproveCurrency.tsapps/cowswap-frontend/src/common/hooks/useSafeApiKit.tsapps/cowswap-frontend/src/modules/erc20Approve/utils/getIsTradeApproveResult.tsapps/cowswap-frontend/src/modules/zeroApproval/hooks/useZeroApprove.tsapps/cowswap-frontend/src/utils/orderUtils/isPermitValidForOrder.tsapps/cowswap-frontend/src/modules/permit/hooks/useGeneratePermitHook.tslibs/core/src/gnosisSafe/index.ts
📚 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/legacy/state/orders/actions.tsapps/cowswap-frontend/src/common/containers/CoWAmmBanner/index.tsxapps/cowswap-frontend/src/common/containers/OrderHooksDetails/HookItem/index.tsxapps/cowswap-frontend/src/common/pure/ReceiveAmountInfo/index.tsxapps/cowswap-frontend/src/common/containers/OrderHooksDetails/index.tsxapps/cowswap-frontend/src/modules/twap/services/fetchTwapOrdersFromSafe.tsapps/cowswap-frontend/src/common/hooks/useOnSelectNetwork.tsxapps/cowswap-frontend/src/common/pure/ConfirmationPendingContent/ConfirmationPendingContentShell.tsxapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeContext.tsapps/cowswap-frontend/src/modules/limitOrders/services/safeBundleFlow/index.tsapps/cowswap-frontend/src/modules/erc20Approve/hooks/useApproveAndSwap.tsapps/cowswap-frontend/src/modules/orderProgressBar/pure/StepComponent.tsxapps/cowswap-frontend/src/common/hooks/useCancelOrder/onChainCancellation.tsapps/cowswap-frontend/src/modules/orderProgressBar/pure/TopSections.tsxapps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsxapps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.tsapps/cowswap-frontend/src/modules/twap/services/cancelTwapOrderTxs.tsapps/cowswap-frontend/src/common/pure/ReceiveAmount/index.tsxapps/cowswap-frontend/src/common/hooks/useGetSurplusFiatValue.tsapps/cowswap-frontend/src/modules/tradeFlow/services/safeBundleFlow/safeBundleEthFlow.tsapps/cowswap-frontend/src/common/updaters/orders/CancelledOrdersUpdater.tsapps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveButton/TradeApproveButton.tsxapps/cowswap-frontend/src/legacy/state/enhancedTransactions/actions.tsapps/cowswap-frontend/src/modules/tradeFlow/services/safeBundleFlow/safeBundleApprovalFlow.tsapps/cowswap-frontend/src/common/hooks/useCancelOrder/useGetOnChainCancellation.tsapps/cowswap-frontend/src/modules/orderProgressBar/pure/RenderProgressTopSection.tsxapps/cowswap-frontend/src/modules/orderProgressBar/pure/LottieContainer.tsxapps/cowswap-frontend/src/modules/twap/services/extensibleFallbackSetupTxs.tsapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeOverview.tsapps/cowswap-frontend/src/common/hooks/useGetMarketDimension.tsapps/cowswap-frontend/src/modules/orderProgressBar/pure/steps/FinishedStep.tsxapps/cowswap-frontend/src/modules/ordersTable/hooks/useDoesOrderHaveValidPermit.test.tsapps/cowswap-frontend/src/modules/erc20Approve/hooks/useApproveCurrency.tsapps/cowswap-frontend/src/common/containers/CoWAmmBanner/types.tsapps/cowswap-frontend/src/modules/erc20Approve/utils/getIsTradeApproveResult.tsapps/cowswap-frontend/src/modules/zeroApproval/hooks/useZeroApprove.tsapps/cowswap-frontend/src/modules/twap/updaters/TwapOrdersUpdater.tsxapps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/NoOrdersContent.tsxapps/cowswap-frontend/src/modules/twap/services/createTwapOrderTxs.tsapps/cowswap-frontend/src/legacy/state/enhancedTransactions/reducer.ts
📚 Learning: 2025-08-05T14:27:05.023Z
Learnt from: alfetopito
Repo: cowprotocol/cowswap PR: 5992
File: libs/wallet/src/web3-react/utils/switchChain.ts:36-38
Timestamp: 2025-08-05T14:27:05.023Z
Learning: In libs/wallet/src/web3-react/utils/switchChain.ts, the team prefers using Record<SupportedChainId, string | null> over Partial<Record<SupportedChainId, string>> for WALLET_RPC_SUGGESTION to enforce that all supported chain IDs have explicit values set, even if some might be null. This ensures compile-time completeness checking.
Applied to files:
apps/cowswap-frontend/src/legacy/state/orders/actions.tsapps/cowswap-frontend/src/modules/twap/services/fetchTwapOrdersFromSafe.tsapps/cowswap-frontend/src/common/hooks/useOnSelectNetwork.tsxapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeContext.tsapps/cowswap-frontend/src/modules/twap/services/cancelTwapOrderTxs.tsapps/cowswap-frontend/src/common/hooks/useEnhancedActivityDerivedState.tslibs/wallet/src/web3-react/updater.tsapps/cowswap-frontend/src/legacy/hooks/useGetSafeTxInfo.tslibs/wallet/src/web3-react/connectors/TrezorConnector/getAccountsList.tsapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeOverview.tsapps/cowswap-frontend/src/common/hooks/useConvertUsdToTokenValue.tsapps/cowswap-frontend/src/modules/ordersTable/hooks/useDoesOrderHaveValidPermit.test.tslibs/wallet/src/web3-react/hooks/useSafeAppsSdk.tslibs/wallet/src/api/types.tsapps/cowswap-frontend/src/common/hooks/useSafeApiKit.tsapps/cowswap-frontend/src/modules/zeroApproval/hooks/useZeroApprove.tsapps/cowswap-frontend/src/utils/orderUtils/isPermitValidForOrder.tsapps/cowswap-frontend/src/legacy/state/enhancedTransactions/reducer.tslibs/core/src/gnosisSafe/index.ts
📚 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/common/containers/CoWAmmBanner/index.tsxapps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsxapps/cowswap-frontend/src/common/pure/ExecutionPrice/hooks/useExecutionPriceFiat.tsapps/cowswap-frontend/src/common/hooks/useConvertUsdToTokenValue.ts
📚 Learning: 2025-09-11T08:25:51.460Z
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.
Applied to files:
apps/cowswap-frontend/src/common/containers/CoWAmmBanner/index.tsxapps/cowswap-frontend/src/common/containers/OrderHooksDetails/HookItem/index.tsxapps/cowswap-frontend/src/common/containers/OrderHooksDetails/index.tsxapps/cowswap-frontend/src/common/hooks/useOnSelectNetwork.tsxapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeContext.tsapps/cowswap-frontend/src/common/updaters/SentryUpdater.tsapps/cowswap-frontend/src/common/hooks/useCancelOrder/onChainCancellation.tsapps/cowswap-frontend/src/modules/orderProgressBar/pure/TopSections.tsxapps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsxapps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.tsapps/cowswap-frontend/src/common/hooks/useGetSurplusFiatValue.tsapps/cowswap-frontend/src/common/hooks/useEnhancedActivityDerivedState.tsapps/cowswap-frontend/src/common/updaters/orders/CancelledOrdersUpdater.tsapps/cowswap-frontend/src/common/hooks/useCancelOrder/useGetOnChainCancellation.tsapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeOverview.tsapps/cowswap-frontend/src/common/hooks/useRateInfoParams.tsapps/cowswap-frontend/src/common/hooks/useConvertUsdToTokenValue.tsapps/cowswap-frontend/src/common/hooks/useSwapResultsContext.tsapps/cowswap-frontend/src/modules/ordersTable/hooks/useDoesOrderHaveValidPermit.test.tsapps/cowswap-frontend/src/common/updaters/WidgetTokensUpdater.tsxapps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/NoOrdersContent.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/common/containers/OrderHooksDetails/HookItem/index.tsxapps/cowswap-frontend/src/common/hooks/useOnSelectNetwork.tsxapps/cowswap-frontend/src/modules/erc20Approve/hooks/useApproveAndSwap.tsapps/cowswap-frontend/src/common/utils/doesOrderHavePermit.tslibs/permit-utils/src/consts/1inchPermitUtils.tsapps/cowswap-frontend/src/modules/ordersTable/utils/checkPermitNonceAndAmount.tsapps/cowswap-frontend/src/modules/ordersTable/utils/extractPermitData.tsapps/cowswap-frontend/src/legacy/hooks/useGetSafeTxInfo.tsapps/cowswap-frontend/src/modules/permit/hooks/useGetCachedPermit.tslibs/permit-utils/src/lib/getPermitUtilsInstance.tslibs/permit-utils/src/lib/checkIsCallDataAValidPermit.tslibs/permit-utils/src/imports/1inchPermitUtils.tsapps/cowswap-frontend/src/modules/ordersTable/hooks/useDoesOrderHaveValidPermit.test.tslibs/wallet/src/web3-react/hooks/useSafeAppsSdk.tslibs/permit-utils/README.mdlibs/permit-utils/src/lib/getTokenPermitInfo.tslibs/permit-utils/src/utils/PermitProviderConnector.tslibs/permit-utils/src/utils/buildPermitCallData.tsapps/cowswap-frontend/src/utils/orderUtils/isPermitValidForOrder.tsapps/cowswap-frontend/src/utils/orderUtils/getOrderPermitAmount.test.tsapps/cowswap-frontend/src/modules/permit/hooks/useGeneratePermitHook.ts
📚 Learning: 2025-09-25T08:49:32.256Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6299
File: apps/cowswap-frontend/src/entities/bridgeProvider/useBridgeSupportedNetworks.test.tsx:62-67
Timestamp: 2025-09-25T08:49:32.256Z
Learning: In the cowswap-frontend codebase, when testing hooks that use multiple bridge providers, both providers are always properly mocked as complete jest.Mocked<BridgeProvider<BridgeQuoteResult>> objects with all required methods stubbed, ensuring no undefined returns that could break the hook logic.
Applied to files:
apps/cowswap-frontend/src/common/containers/OrderHooksDetails/HookItem/index.tsxapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeContext.tsapps/cowswap-frontend/src/legacy/hooks/useGetSafeTxInfo.tsapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeOverview.ts
📚 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/common/pure/ReceiveAmountInfo/index.tsxapps/cowswap-frontend/src/common/pure/CoWAmmBannerContent/index.tsxapps/cowswap-frontend/src/common/pure/ReceiveAmount/index.tsxapps/cowswap-frontend/src/common/pure/CurrencyInputPanel/types.tseslint.config.js
📚 Learning: 2025-09-25T08:48:53.495Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6299
File: apps/cowswap-frontend/src/entities/bridgeProvider/useBridgeSupportedNetworks.test.tsx:58-60
Timestamp: 2025-09-25T08:48:53.495Z
Learning: In the cowswap-frontend codebase, when writing SWR tests, the team prefers maximum test isolation by using `provider: () => new Map()` in SWRConfig wrappers, even if it recreates cache on every render, to ensure tests don't share any state.
Applied to files:
apps/cowswap-frontend/src/common/containers/OrderHooksDetails/index.tsxapps/cowswap-frontend/src/common/hooks/useEnhancedActivityDerivedState.tsapps/cowswap-frontend/src/modules/ordersTable/hooks/useDoesOrderHaveValidPermit.test.ts
📚 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/common/hooks/useOnSelectNetwork.tsxapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeContext.tsapps/cowswap-frontend/src/modules/twap/services/cancelTwapOrderTxs.tsapps/cowswap-frontend/src/common/hooks/useEnhancedActivityDerivedState.tsapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeOverview.tsapps/cowswap-frontend/src/common/hooks/useConvertUsdToTokenValue.ts
📚 Learning: 2025-04-02T09:58:29.374Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 5549
File: apps/cowswap-frontend/src/modules/tradeFlow/services/safeBundleFlow/safeBundleEthFlow.ts:152-152
Timestamp: 2025-04-02T09:58:29.374Z
Learning: In the `safeBundleEthFlow` function, `account` is guaranteed to be truthy based on the type system (`PostOrderParams` defines it as a required string) and the context in which the function is called, so additional runtime checks are unnecessary.
Applied to files:
apps/cowswap-frontend/src/modules/limitOrders/services/safeBundleFlow/index.tsapps/cowswap-frontend/src/modules/tradeFlow/services/safeBundleFlow/safeBundleEthFlow.tsapps/cowswap-frontend/src/modules/onchainTransactions/updaters/FinalizeTxUpdater/services/checkSafeTransaction.tsapps/cowswap-frontend/src/modules/tradeFlow/services/safeBundleFlow/safeBundleApprovalFlow.tslibs/wallet/src/web3-react/updater.tsapps/cowswap-frontend/src/modules/ordersTable/utils/checkPermitNonceAndAmount.ts
📚 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/hooks/useApproveAndSwap.tsapps/cowswap-frontend/src/modules/twap/services/cancelTwapOrderTxs.tsapps/cowswap-frontend/src/common/hooks/useSwapAndBridgeOverview.tsapps/cowswap-frontend/src/common/hooks/useSwapResultsContext.ts
📚 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/common/updaters/orders/UnfillableOrdersUpdater/hooks/useUpdateIsUnfillableFlag.tsapps/cowswap-frontend/src/common/updaters/orders/OrdersFromApiUpdater.tsapps/cowswap-frontend/src/common/updaters/orders/SpotPricesUpdater.tslibs/wallet/src/web3-react/updater.tsapps/cowswap-frontend/src/common/updaters/orders/UnfillableOrdersUpdater/updaters/UnfillableOrderUpdater.tslibs/permit-utils/src/lib/getTokenPermitInfo.tsapps/cowswap-frontend/src/common/updaters/WidgetTokensUpdater.tsxapps/cowswap-frontend/src/common/updaters/orders/PendingOrdersUpdater.tsapps/cowswap-frontend/src/modules/twap/updaters/TwapOrdersUpdater.tsx
📚 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/common/updaters/orders/UnfillableOrdersUpdater/hooks/useUpdateIsUnfillableFlag.tsapps/cowswap-frontend/src/common/updaters/orders/OrdersFromApiUpdater.tsapps/cowswap-frontend/src/common/hooks/useCancelOrder/useSendOnChainCancellation.tsapps/cowswap-frontend/src/common/hooks/useCancelOrder/useGetOnChainCancellation.tsapps/cowswap-frontend/src/common/updaters/orders/SpotPricesUpdater.tsapps/cowswap-frontend/src/common/updaters/orders/UnfillableOrdersUpdater/updaters/UnfillableOrderUpdater.tsapps/cowswap-frontend/src/common/containers/CoWAmmBanner/types.tsapps/cowswap-frontend/src/common/updaters/orders/PendingOrdersUpdater.ts
📚 Learning: 2025-06-16T16:01:46.729Z
Learnt from: alfetopito
Repo: cowprotocol/cowswap PR: 5831
File: apps/cowswap-frontend/src/modules/application/containers/AppMenu/index.tsx:7-9
Timestamp: 2025-06-16T16:01:46.729Z
Learning: React Router v7 restructured packages - NavLink and other core routing components should be imported from 'react-router' (not 'react-router-dom'). In v7, 'react-router-dom' mainly re-exports for backward compatibility, while 'react-router' is the new preferred import path for most components.
Applied to files:
apps/cowswap-frontend/src/common/hooks/useNavigate.tseslint.config.js
📚 Learning: 2025-06-16T16:01:46.729Z
Learnt from: alfetopito
Repo: cowprotocol/cowswap PR: 5831
File: apps/cowswap-frontend/src/modules/application/containers/AppMenu/index.tsx:7-9
Timestamp: 2025-06-16T16:01:46.729Z
Learning: In React Router v6+, NavLink can be imported directly from 'react-router' package, not just 'react-router-dom'. The package structure has evolved and the import from 'react-router' is valid for the latest versions.
Applied to files:
apps/cowswap-frontend/src/common/hooks/useNavigate.ts
📚 Learning: 2025-09-24T14:52:37.874Z
Learnt from: cowdan
Repo: cowprotocol/cowswap PR: 6285
File: apps/cowswap-frontend/src/modules/swap/updaters/index.tsx:49-53
Timestamp: 2025-09-24T14:52:37.874Z
Learning: UnfillableOrdersUpdater instances can be safely mounted in multiple locations (SwapUpdaters and OrdersTableWidget) because they use window visibility checks to prevent simultaneous network calls, ensuring only one instance makes API requests at a time.
Applied to files:
apps/cowswap-frontend/src/common/updaters/orders/UnfillableOrdersUpdater/updaters/UnfillableOrderUpdater.ts
📚 Learning: 2025-12-03T19:23:35.789Z
Learnt from: kernelwhisperer
Repo: cowprotocol/cowswap PR: 6610
File: apps/cowswap-frontend/project.json:38-39
Timestamp: 2025-12-03T19:23:35.789Z
Learning: In the cowswap-frontend project configuration (apps/cowswap-frontend/project.json), the Vite dev server option `"host": true` is set to support Windows + WSL development environments, where binding to all network interfaces is required for the Windows host to access the dev server running in WSL.
Applied to files:
apps/cowswap-frontend/vite.config.mts
📚 Learning: 2025-08-12T06:33:19.348Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6137
File: libs/tokens/src/state/tokens/allTokensAtom.ts:34-65
Timestamp: 2025-08-12T06:33:19.348Z
Learning: In libs/tokens/src/utils/parseTokenInfo.ts, the parseTokenInfo() function returns a new instance of TokenInfo using object spread syntax ({ ...token, ... }), making it safe to mutate properties like lpTokenProvider on the returned object without side effects.
Applied to files:
apps/cowswap-frontend/src/common/containers/CoWAmmBanner/types.tslibs/permit-utils/src/lib/getTokenPermitInfo.ts
📚 Learning: 2025-08-12T06:33:19.348Z
Learnt from: shoom3301
Repo: cowprotocol/cowswap PR: 6137
File: libs/tokens/src/state/tokens/allTokensAtom.ts:34-65
Timestamp: 2025-08-12T06:33:19.348Z
Learning: In libs/tokens/src/state/tokens/allTokensAtom.ts, the parseTokenInfo() function returns a new instance of TokenInfo each time, making it safe to mutate properties like lpTokenProvider on the returned object without side effects.
Applied to files:
apps/cowswap-frontend/src/common/containers/CoWAmmBanner/types.tslibs/permit-utils/src/lib/getTokenPermitInfo.ts
🧬 Code graph analysis (12)
apps/cowswap-frontend/src/modules/onchainTransactions/updaters/FinalizeTxUpdater/services/checkSafeTransaction.ts (1)
apps/cowswap-frontend/src/modules/onchainTransactions/updaters/FinalizeTxUpdater/services/handleTransactionReplacement.ts (1)
handleTransactionReplacement(8-18)
apps/cowswap-frontend/src/modules/orderProgressBar/pure/RenderProgressTopSection.tsx (3)
apps/cowswap-frontend/src/modules/orderProgressBar/pure/ProgressSkeleton.tsx (1)
ProgressSkeleton(71-90)apps/cowswap-frontend/src/modules/orderProgressBar/pure/styled.ts (1)
ProgressTopSection(75-92)apps/cowswap-frontend/src/modules/orderProgressBar/pure/ProgressTopSection/index.tsx (1)
ProgressTopSection(32-95)
libs/wallet/src/web3-react/updater.ts (1)
libs/core/src/gnosisSafe/index.ts (1)
getSafeInfo(81-90)
apps/cowswap-frontend/src/modules/ordersTable/utils/checkPermitNonceAndAmount.ts (2)
libs/permit-utils/src/index.ts (1)
getPermitUtilsInstance(5-5)libs/permit-utils/src/lib/getPermitUtilsInstance.ts (1)
getPermitUtilsInstance(17-51)
apps/cowswap-frontend/src/legacy/hooks/useGetSafeTxInfo.ts (3)
libs/wallet/src/api/hooks.ts (1)
useWalletInfo(24-26)libs/core/src/gnosisSafe/index.ts (2)
getSafeInfo(81-90)getSafeTransaction(71-79)apps/explorer/src/utils/miscellaneous.ts (1)
retry(120-138)
tools/formatChunkFileName.ts (1)
apps/cowswap-frontend/public/emergency.js (1)
key(22-22)
libs/permit-utils/src/lib/checkIsCallDataAValidPermit.ts (2)
libs/permit-utils/src/imports/1inchPermitUtils.ts (1)
Eip2612PermitUtils(10-10)libs/permit-utils/src/types.ts (1)
PermitInfo(8-13)
apps/cowswap-frontend/src/modules/orderProgressBar/pure/steps/FinishedStep.tsx (1)
apps/cowswap-frontend/src/modules/orderProgressBar/pure/steps/styled.ts (1)
TransactionStatus(262-291)
apps/cowswap-frontend/vite.config.mts (1)
tools/formatChunkFileName.ts (1)
formatChunkFileName(3-20)
apps/cowswap-frontend/src/common/hooks/useSafeApiKit.ts (3)
libs/wallet/src/api/hooks.ts (1)
useWalletInfo(24-26)libs/wallet/src/web3-react/hooks/useWalletMetadata.ts (1)
useIsSafeWallet(133-135)libs/core/src/gnosisSafe/index.ts (1)
createSafeApiKitInstance(39-48)
libs/permit-utils/src/lib/getTokenPermitInfo.ts (2)
libs/permit-utils/src/index.ts (1)
getPermitUtilsInstance(5-5)libs/permit-utils/src/lib/getPermitUtilsInstance.ts (1)
getPermitUtilsInstance(17-51)
apps/cowswap-frontend/src/lib/i18n.tsx (2)
jest.setup.ts (1)
i18n(51-51)libs/common-const/src/locales.ts (1)
DEFAULT_LOCALE(10-10)
🪛 Biome (2.1.2)
apps/cowswap-frontend/src/modules/orderProgressBar/pure/LottieContainer.tsx
[error] 65-65: Wrap comments inside children within braces.
Unsafe fix: Wrap the comments with braces
(lint/suspicious/noCommentText)
apps/cowswap-frontend/src/modules/orderProgressBar/pure/steps/FinishedStep.tsx
[error] 39-39: Wrap comments inside children within braces.
Unsafe fix: Wrap the comments with braces
(lint/suspicious/noCommentText)
apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/NoOrdersContent.tsx
[error] 107-107: Wrap comments inside children within braces.
Unsafe fix: Wrap the comments with braces
(lint/suspicious/noCommentText)
⏰ 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
| threshold, | ||
| owners, | ||
| nonce, | ||
| nonce: String(nonce), |
There was a problem hiding this comment.
Verify nonce type consistency across both code paths.
Line 95 explicitly converts nonce to a string when using the Safe Apps SDK, but line 114 assigns nonce directly from the getSafeInfo API without conversion. This inconsistency could cause type mismatches in the GnosisSafeInfo object if the two sources return different types.
Given that the PR migrates to new @safe-global/** versions with type changes, ensure both paths produce the same nonce type. Consider applying String() conversion on line 114 as well, or verify that both APIs return string values.
🔎 Proposed fix to ensure consistent nonce type handling
const _safeInfo = await getSafeInfo(chainId, account)
const { address, threshold, owners, nonce } = _safeInfo
setSafeInfo((prevSafeInfo) => ({
...prevSafeInfo,
chainId,
address,
threshold,
owners,
- nonce,
+ nonce: String(nonce),
isReadOnly: false,
}))Also applies to: 114-114
🤖 Prompt for AI Agents
In libs/wallet/src/web3-react/updater.ts around lines 95 and 114, the nonce is
explicitly converted to a string at line 95 but assigned raw at line 114,
causing inconsistent types in the GnosisSafeInfo object; make the nonce type
consistent by converting the value at line 114 to a string (e.g., wrap with
String(...) or otherwise coerce to string) so both code paths produce the same
nonce type and update any related typings if necessary.
There was a problem hiding this comment.
@crutch12, understood! Thank you for clarifying. If the Safe Apps SDK returns a number while the getSafeInfo API returns a string in the new version, then the different handling makes sense. Appreciate the confirmation! 👍
🧠 Learnings used
Learnt from: alfetopito
Repo: cowprotocol/cowswap PR: 5992
File: libs/wallet/src/web3-react/utils/switchChain.ts:36-38
Timestamp: 2025-08-05T14:27:05.023Z
Learning: In libs/wallet/src/web3-react/utils/switchChain.ts, the team prefers using Record<SupportedChainId, string | null> over Partial<Record<SupportedChainId, string>> for WALLET_RPC_SUGGESTION to enforce that all supported chain IDs have explicit values set, even if some might be null. This ensures compile-time completeness checking.
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.
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: 5549
File: apps/cowswap-frontend/src/modules/tradeFlow/services/safeBundleFlow/safeBundleEthFlow.ts:152-152
Timestamp: 2025-04-02T09:58:29.374Z
Learning: In the `safeBundleEthFlow` function, `account` is guaranteed to be truthy based on the type system (`PostOrderParams` defines it as a required string) and the context in which the function is called, so additional runtime checks are unnecessary.
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
apps/cowswap-frontend/src/modules/orderProgressBar/pure/LottieContainer.tsx (1)
65-73: JSX comment syntax fixed; consider a loading skeleton.The invalid JSX comment from the previous review has been corrected. The Suspense wrapper is properly implemented with a valid
fallback={null}.Since the TODO already flags this, consider whether a loading skeleton or placeholder would improve UX by preventing a brief flash when the Lottie animation loads. For a progress indicator,
nullmay be acceptable if the load is fast enough.apps/cowswap-frontend/vite.config.mts (1)
182-190: Manual chunks configuration looks good.The chunking strategy for large dependencies (
@sentry,@uniswap,@ethersproject, etc.) is sensible for code splitting. Thebn.jschunk complements thededupesetting above.One minor note: the comment on line 187 states web3 "was used by @1inch" - if @1inch no longer uses web3 after this refactor, consider verifying this chunk is still needed.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (7)
CONTRIBUTING.mdapps/cowswap-frontend/src/modules/orderProgressBar/pure/LottieContainer.tsxapps/cowswap-frontend/src/modules/orderProgressBar/pure/TopSections.tsxapps/cowswap-frontend/src/modules/orderProgressBar/pure/steps/FinishedStep.tsxapps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/NoOrdersContent.tsxapps/cowswap-frontend/vite.config.mtspackage.json
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/cowswap-frontend/src/modules/orderProgressBar/pure/steps/FinishedStep.tsx
- apps/cowswap-frontend/src/modules/orderProgressBar/pure/TopSections.tsx
- apps/cowswap-frontend/src/modules/ordersTable/pure/OrdersTableContainer/NoOrdersContent.tsx
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
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.
📚 Learning: 2025-07-28T16:26:08.051Z
Learnt from: cowdan
Repo: cowprotocol/cowswap PR: 6034
File: apps/cowswap-frontend-e2e/src/e2e/fiat-amounts.test.ts:44-47
Timestamp: 2025-07-28T16:26:08.051Z
Learning: In the cowswap codebase, using trivial placeholder tests like `it('should be true', () => { expect(true).to.be.true })` in e2e test files is an intentional pattern when disabling broken tests to keep CI green while maintaining build efficiency.
Applied to files:
CONTRIBUTING.md
📚 Learning: 2025-12-03T19:23:35.789Z
Learnt from: kernelwhisperer
Repo: cowprotocol/cowswap PR: 6610
File: apps/cowswap-frontend/project.json:38-39
Timestamp: 2025-12-03T19:23:35.789Z
Learning: In the cowswap-frontend project configuration (apps/cowswap-frontend/project.json), the Vite dev server option `"host": true` is set to support Windows + WSL development environments, where binding to all network interfaces is required for the Windows host to access the dev server running in WSL.
Applied to files:
apps/cowswap-frontend/vite.config.mts
📚 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/orderProgressBar/pure/LottieContainer.tsx
🧬 Code graph analysis (1)
apps/cowswap-frontend/vite.config.mts (1)
tools/formatChunkFileName.ts (1)
formatChunkFileName(3-20)
🪛 LanguageTool
CONTRIBUTING.md
[grammar] ~168-~168: Use a hyphen to join words.
Context: ...ially if it's cjs module (cjs is non tree-shakable) - [Bundlephobia](https://...
(QB_NEW_EN_HYPHEN)
⏰ 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 (13)
CONTRIBUTING.md (3)
155-156: Verify build analysis output paths are implemented.The documentation references
build/cowswap/analyse.htmlandbuild/cowswap/bundle-stats.html, but the PR objectives list "Add rollup-plugin-bundle-stats" as a TODO. Ensure these output paths are available and that theyarn analyze-buildcommand is properly configured before merging, or update the guidance to reflect the current state of implementation.
151-171: Bundle optimization section is well-structured and actionable.The new section provides clear, practical guidance aligned with the PR's bundle optimization objectives. The problem-detection steps, dynamic import rules, and dependency-size considerations are directly applicable to contributors and enforce key optimization patterns introduced in this PR.
173-194: Section numbering correctly updated after restructuring.All downstream sections (Testing, Interaction Contract, Development Communication) are properly renumbered to account for the new Bundle optimization section.
apps/cowswap-frontend/src/modules/orderProgressBar/pure/LottieContainer.tsx (1)
1-1: LGTM! Lazy loading correctly implemented.The lazy import of
lottie-reactfollows the standard React.lazy pattern and aligns with the PR's bundle optimization goals. This will defer loading the Lottie library until the component is actually rendered.Also applies to: 5-5
apps/cowswap-frontend/vite.config.mts (6)
5-5: LGTM on imports and type annotations.The new imports for
bundleStats,formatChunkFileName, and type-only imports forTemplateTypeandPluginOptionare correctly structured. The ESLint directive update to@typescript-eslint/no-restricted-importsaligns with the broader rule transition in this PR.Also applies to: 17-17, 21-23
37-37: Good addition of explicit type annotation.Typing
pluginsasPluginOption[]improves type safety and aligns with the casts used when pushing analyzer plugins.
75-87: Verify intended behavior withopen: trueandemitFile: true.With
emitFile: true, the analysis HTML will be written to the build output directory. Note thatopen: true(line 79) combined withemitFile: truemay still attempt to open the file in a browser after the build. If the intent is only to emit the file without opening it, consider settingopen: false.
138-143: Good ESM prioritization for dependency optimization.Setting
mainFields: ['exports', 'module', 'main']ensures esbuild prefers ESM builds when available, improving tree-shaking effectiveness. The comment appropriately documents the rationale.
149-154: Effective deduplication and ESM resolution strategy.The
bn.jsdeduplication with the v5/v4 compatibility note is a good optimization. Theconditionsarray correctly prioritizes ESM resolution. These settings work well together with theoptimizeDeps.mainFieldsconfiguration above.
169-181: Improved chunk naming for better debuggability.The
formatChunkFileNamehelper with descriptive prefixes (page-,connectors-,lottie-react-, etc.) makes it much easier to identify chunk origins in build output and DevTools. The fallback tostatic/[name]-[hash].jsensures all chunks are handled.package.json (3)
46-46: LGTM: Improved visualization format.The treemap template generally provides better visibility for bundle size analysis compared to sunburst.
93-93: LGTM: New dependency addition.The @ethereumjs/util package is properly versioned with a caret for receiving updates.
338-338: No action needed. Therollup-plugin-bundle-statspackage is properly integrated into the Vite build configuration (imported and added to the plugins array in vite.config.mts).Likely an incorrect or invalid review comment.
| "@safe-global/api-kit": "^4.0.1", | ||
| "@safe-global/safe-apps-sdk": "^9.1.0", | ||
| "@safe-global/safe-core-sdk-types": "^2.2.0", | ||
| "@safe-global/safe-ethers-lib": "^1.9.4", | ||
| "@safe-global/types-kit": "^3.0.0", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find all usages of Safe Global types and nonce handling
rg -n --type=ts --type=tsx 'SafeMultisigTransactionResponse|SafeApiKit|nonce' --max-count=50Repository: cowprotocol/cowswap
Length of output: 90
🏁 Script executed:
# Check for test files related to Safe operations
fd -e 'test.ts' -e 'test.tsx' -e 'spec.ts' -e 'spec.tsx' | xargs rg -l 'Safe|nonce' 2>/dev/null | head -20Repository: cowprotocol/cowswap
Length of output: 623
🏁 Script executed:
# Look for the actual Safe Global package versions and their changelog implications
rg -n '@safe-global' package.jsonRepository: cowprotocol/cowswap
Length of output: 352
🏁 Script executed:
# Search for SafeApiKit usage patterns in the codebase
rg -n 'SafeApiKit' --type=ts --type=tsx -B2 -A5Repository: cowprotocol/cowswap
Length of output: 90
🏁 Script executed:
# Search for SafeApiKit and SafeMultisigTransactionResponse usage
rg -n 'SafeApiKit|SafeMultisigTransactionResponse' --type=ts --max-count=30Repository: cowprotocol/cowswap
Length of output: 5579
🏁 Script executed:
# Search for nonce handling patterns
rg -n 'nonce' --type=ts apps/cowswap-frontend/ | head -30Repository: cowprotocol/cowswap
Length of output: 4892
🏁 Script executed:
# Find where Safe Global types are imported
rg -n 'from.*@safe-global' --type=ts --max-count=30Repository: cowprotocol/cowswap
Length of output: 3094
🏁 Script executed:
# Check the actual Safe approval-related code mentioned in learnings
cat apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.tsRepository: cowprotocol/cowswap
Length of output: 5470
🏁 Script executed:
# Check test coverage in Safe-related test files
cat apps/explorer/src/test/hooks/useSafeState.hooks.test.tsxRepository: cowprotocol/cowswap
Length of output: 2040
🏁 Script executed:
# Check useTradeApproveCallback test file to see what's tested
head -100 apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.test.tsRepository: cowprotocol/cowswap
Length of output: 4213
🏁 Script executed:
# Search for TODO or FIXME related to testing in Safe modules
rg -n 'TODO|FIXME' --type=ts apps/cowswap-frontend/src/modules/zeroApproval/ apps/cowswap-frontend/src/modules/twap/ libs/core/src/gnosisSafe/Repository: cowprotocol/cowswap
Length of output: 7331
🏁 Script executed:
# Verify SafeApiKit instantiation and version compatibility
cat libs/core/src/gnosisSafe/index.tsRepository: cowprotocol/cowswap
Length of output: 3556
🏁 Script executed:
# Check Safe-related test implementations
cat apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.test.ts | tail -200Repository: cowprotocol/cowswap
Length of output: 7133
🏁 Script executed:
# Look for Safe scenario tests
rg -n 'Safe|nonce|safeApiKit' apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.test.tsRepository: cowprotocol/cowswap
Length of output: 82
🏁 Script executed:
# Check if there are integration tests for Safe flows
fd -path '*/test*' -o -path '*/spec*' | xargs rg -l 'SafeApiKit\|SafeMultisigTransactionResponse' 2>/dev/nullRepository: cowprotocol/cowswap
Length of output: 233
🏁 Script executed:
# Search for actual Safe wallet test coverage in approval flows
rg -n 'Safe|safeMultisig|safeApiKit' --type=ts apps/cowswap-frontend/src/modules/erc20Approve/ apps/cowswap-frontend/src/modules/zeroApproval/ -i | grep -i testRepository: cowprotocol/cowswap
Length of output: 45
🏁 Script executed:
# Check if there are dedicated Safe approval integration tests
find apps/cowswap-frontend -name '*.test.ts' -o -name '*.test.tsx' | xargs rg -l 'SafeMultisigTransactionResponse|useApproveCurrency|useZeroApprove' 2>/dev/nullRepository: cowprotocol/cowswap
Length of output: 257
🏁 Script executed:
# Look at the actual useApproveCurrency hook which handles Safe responses
cat apps/cowswap-frontend/src/modules/erc20Approve/hooks/useApproveCurrency.tsRepository: cowprotocol/cowswap
Length of output: 1198
🏁 Script executed:
# Check for useZeroApprove tests
find apps/cowswap-frontend -name '*useZeroApprove*test*'Repository: cowprotocol/cowswap
Length of output: 45
🏁 Script executed:
# Check for useApproveCurrency tests
find apps/cowswap-frontend -name '*useApproveCurrency*test*'Repository: cowprotocol/cowswap
Length of output: 45
🏁 Script executed:
# Look at useZeroApprove implementation to understand its Safe interaction
cat apps/cowswap-frontend/src/modules/zeroApproval/hooks/useZeroApprove.tsRepository: cowprotocol/cowswap
Length of output: 2568
Add test coverage for Safe wallet approval flows.
The Safe Global package updates are properly integrated with BigInt chainId conversion already in place (libs/core/src/gnosisSafe/index.ts) and defensive nonce type handling established. However, the approval flows lack dedicated test coverage for Safe-specific scenarios:
useZeroApprovedirectly callsSafeApiKit.getTransaction()and polls for transaction execution withwaitForSafeTransactionExecution()— needs tests for this polling behavior and Safe wallet detection conditionsuseApproveCurrencycombines trade approval with zero approval but has no tests- Current test coverage focuses on standard transactions; Safe wallet scenarios (isSafeWallet + isWalletConnect conditional logic) are untested
Add tests for Safe transaction execution flows, Safe wallet routing, and transaction polling edge cases before merging.
🤖 Prompt for AI Agents
In package.json around lines 119 to 121, tests for Safe wallet approval flows
are missing; add unit/integration tests that mock SafeApiKit.getTransaction and
waitForSafeTransactionExecution to cover polling behavior, simulate Safe wallet
detection (isSafeWallet true/false and isWalletConnect branches), and assert
useZeroApprove and useApproveCurrency handle zero-approval flow, combined
approval flow, retries, and timeout/edge cases; update test
scripts/devDependencies as needed to run these tests and ensure mocks restore
state between cases.
| "@walletconnect/ethereum-provider": "^2.23.0", | ||
| "@walletconnect/types": "^2.23.0", | ||
| "@walletconnect/utils": "^2.23.0", |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
@walletconnect/ethereum-provider latest version npm
💡 Result:
Latest version: 2.21.8 (as of December 28, 2025). Install: npm i @walletconnect/ethereum-provider. [1]
Sources:
[1] npm package page for @walletconnect/ethereum-provider. [2] jsDelivr package info.
🌐 Web query:
WalletConnect v2 deprecated Reown migration 2024
💡 Result:
Short summary — yes: WalletConnect Inc. rebranded to Reown and deprecated the WalletConnect-branded SDK packages (including v2 SDK packages under the WalletConnect org). A limited‑support window ran Sept 17, 2024 → Feb 17, 2025; full end‑of‑life (no updates/support) began Feb 18, 2025. Reown published replacement packages (AppKit / WalletKit, Reown org repos) and migration guides for Web, React Native, Swift, Flutter, etc. Action: identify which WalletConnect packages you use, follow the corresponding Reown migration guide (replace @walletconnect/* / Web3Modal / Web3Wallet with @reown/* equivalents), and complete migration to Reown packages. [1][2][3]
Sources:
- Reown — Deprecated WalletConnect SDKs (deprecation schedule + affected packages). [1]
- WalletConnect / Reown migration docs — Upgrade from Web3Wallet to Reown WalletKit (migration steps). [2]
- Reown announcement / rebrand blog. [3]
🌐 Web query:
@walletconnect/types @walletconnect/utils latest version
💡 Result:
As of today (December 28, 2025):
- @walletconnect/types — 2.21.8. Install: npm i @walletconnect/types. [1]
- @walletconnect/utils — 2.21.8. Install: npm i @walletconnect/utils. [2]
Sources: npm package pages. [1] https://www.npmjs.com/package/%40walletconnect/types [2] https://www.npmjs.com/package/%40walletconnect/utils
Migrate from deprecated WalletConnect v2 packages to Reown equivalents—this is critical.
The @WalletConnect v2 packages (@walletconnect/ethereum-provider, @walletconnect/types, @walletconnect/utils) reached end-of-life on February 18, 2025 and no longer receive updates or support. WalletConnect Inc. rebranded to Reown and deprecated the entire v2 SDK. Migration to @reown/* packages (AppKit/WalletKit) is required. Additionally, version 2.23.0 does not appear to exist on npm; the latest v2 release is 2.21.8—verify the actual resolved versions and migrate to Reown's replacement packages per their official migration guides.
| }, | ||
| "dependencies": { | ||
| "@1inch/permit-signed-approvals-utils": "^1.4.10", | ||
| "@1inch/permit-signed-approvals-utils": "1.5.1", |
| "@rjsf/core": "^4.2.2", | ||
| "@safe-global/api-kit": "^1.3.0", | ||
| "@safe-global/protocol-kit": "^1.2.0", | ||
| "@safe-global/api-kit": "^4.0.1", |
There was a problem hiding this comment.
@elena-zh please test integration with Safe (web/walletConnect)
| )} | ||
| </motion.div> | ||
| </AnimatePresence> | ||
| <Suspense fallback={<ProgressSkeleton />}> |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@crutch12 thank you! |
… refactor/swap-bundle-optimization # Conflicts: # libs/wallet/src/web3-react/updater.ts
… refactor/swap-bundle-optimization # Conflicts: # apps/cowswap-frontend/patches/@1inch+permit-signed-approvals-utils+1.4.10.patch # apps/cowswap-frontend/patches/@1inch+permit-signed-approvals-utils+1.5.1.patch # apps/cowswap-frontend/src/common/hooks/useCancelOrder/onChainCancellation.ts # apps/cowswap-frontend/src/modules/ordersTable/hooks/useDoesOrderHaveValidPermit.test.ts # apps/cowswap-frontend/src/utils/orderUtils/getOrderPermitAmount.test.ts # apps/cowswap-frontend/src/utils/orderUtils/isPermitValidForOrder.ts # eslint.config.js # libs/permit-utils/package.json # package.json # patches/@1inch+permit-signed-approvals-utils+1.4.10.patch # yarn.lock
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@apps/cowswap-frontend/src/locales/en-US.po`:
- Around line 5957-5958: The msgid "There is no provider to get Gnosis safe
info" is marked obsolete in en-US.po but remains active in other locale catalogs
(el-GR, es-ES, tr-TR, ru-RU, pt-BR, pl-PL); either mark this msgid obsolete
across those locale files to match en-US or re-extract/sync all translation
catalogs so the msgid is consistently present or removed in every locale,
updating the corresponding .po entries to match (use the msgid string to locate
entries).
In `@libs/wallet/package.json`:
- Around line 40-45: Remove the unused legacy dependency "ethereumjs-util" from
package.json and keep the modern "@ethereumjs/util" v10.1.0 in place;
specifically delete the "ethereumjs-util" entry, run the package manager to
update lockfiles (npm/yarn/pnpm install), and verify imports in
libs/wallet/src/web3-react/connectors/TrezorConnector/getAccountsList.ts still
reference "@ethereumjs/util" (not "ethereumjs-util") so nothing breaks.
🧹 Nitpick comments (4)
apps/cowswap-frontend/src/locales/en-US.po (1)
2586-2587: Keep other locale catalogs in sync for the re-enabled copy.Since this msgid is active again, please ensure other locale
.pocatalogs have active entries too, otherwise non‑English users may see fallbacks.apps/cowswap-frontend/vite.config.mts (1)
179-186: Remove the unused web3 chunk configuration.The
web3/distchunk is dead code—web3 is not imported anywhere in the cowswap-frontend app and is not listed as a dependency in its package.json. Even though@1inchremains a dependency, there's no evidence it requires web3. This chunk can be safely removed.libs/wallet/package.json (1)
40-40: Consider removing the legacyethereumjs-utilpackage.Both
@ethereumjs/util(v10, line 40) andethereumjs-util(v7, line 55) are present. The@ethereumjs/utilpackage is the modern ESM rewrite, whileethereumjs-utilis the legacy CommonJS package. Since this PR focuses on bundle optimization and ESM migration, keeping both adds redundant code to the bundle.#!/bin/bash # Description: Check if ethereumjs-util (legacy) is still being used # Expect: If no direct imports, the legacy package can be removed echo "=== Imports from legacy ethereumjs-util ===" rg -n "from 'ethereumjs-util'|from \"ethereumjs-util\"|require\('ethereumjs-util'\)" --type ts --type js echo "" echo "=== Imports from modern `@ethereumjs/util` ===" rg -n "from '@ethereumjs/util'|from \"@ethereumjs/util\"" --type ts --type jsAlso applies to: 55-55
apps/explorer/tsconfig.json (1)
11-11: Reconsider disablingnoImplicitAny.
This overrides the stricter setting intsconfig.base.jsonand contradictsstrict: true. EnablingnoImplicitAny: truewould strengthen type safety. The codebase has untyped callback parameters (e.g.,.catch((error) =>and.map((item) =>) that would need explicit type annotations, but this is worthwhile for preventing regressions.♻️ Proposed change
- "noImplicitAny": false + "noImplicitAny": true
| #~ msgid "There is no provider to get Gnosis safe info" | ||
| #~ msgstr "There is no provider to get Gnosis safe info" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for any remaining usage of the msgid in code
rg -n "There is no provider to get Gnosis safe info"Repository: cowprotocol/cowswap
Length of output: 877
🏁 Script executed:
#!/bin/bash
# Search for code references to this message (excluding .po files)
rg -n "Gnosis safe info" --type-not poRepository: cowprotocol/cowswap
Length of output: 45
🏁 Script executed:
#!/bin/bash
# Search for any "Gnosis safe" references in code
rg "Gnosis safe" --type-not poRepository: cowprotocol/cowswap
Length of output: 464
Remove obsolete marking or synchronize all locale files.
The string is confirmed unused in code, so marking it obsolete in en-US.po is appropriate. However, 6 other locale files (el-GR.po, es-ES.po, tr-TR.po, ru-RU.po, pt-BR.po, pl-PL.po) still have this msgid as active entries. Either mark it obsolete consistently across all locales or re-extract catalogs to synchronize all translation files.
🤖 Prompt for AI Agents
In `@apps/cowswap-frontend/src/locales/en-US.po` around lines 5957 - 5958, The
msgid "There is no provider to get Gnosis safe info" is marked obsolete in
en-US.po but remains active in other locale catalogs (el-GR, es-ES, tr-TR,
ru-RU, pt-BR, pl-PL); either mark this msgid obsolete across those locale files
to match en-US or re-extract/sync all translation catalogs so the msgid is
consistently present or removed in every locale, updating the corresponding .po
entries to match (use the msgid string to locate entries).
| "@ethereumjs/util": "^10.1.0", | ||
| "@metamask/jazzicon": "^2.0.0", | ||
| "@metamask/sdk": "^0.31.4", | ||
| "@safe-global/api-kit": "^1.3.0", | ||
| "@safe-global/api-kit": "^4.0.1", | ||
| "@safe-global/safe-apps-sdk": "^9.1.0", | ||
| "@safe-global/safe-core-sdk-types": "^2.2.0", | ||
| "@safe-global/types-kit": "^3.0.0", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find all usages of SafeApiKit and Safe types
echo "=== SafeApiKit instantiation patterns ==="
rg -n 'SafeApiKit' --type ts --type tsx | head -30
echo ""
echo "=== Imports from `@safe-global` packages (old and new) ==="
rg -n 'from ["\x27]@safe-global/(api-kit|types-kit|safe-core-sdk-types)' --type ts --type tsx
echo ""
echo "=== SafeMultisigTransactionResponse usage ==="
rg -n 'SafeMultisigTransactionResponse' --type ts --type tsx
echo ""
echo "=== ethereumjs-util vs `@ethereumjs/util` usage ==="
rg -n 'from ["\x27](ethereumjs-util|@ethereumjs/util)' --type ts --type tsxRepository: cowprotocol/cowswap
Length of output: 389
🏁 Script executed:
#!/bin/bash
# Check which Safe types are being imported and from where
echo "=== All imports containing 'Safe' from `@safe-global` ==="
rg -n 'import.*from.*@safe-global' --type ts --type tsx -A 1 | head -50
echo ""
echo "=== Check package.json for both ethereumjs packages ==="
rg -n 'ethereumjs' libs/wallet/package.jsonRepository: cowprotocol/cowswap
Length of output: 294
🏁 Script executed:
#!/bin/bash
# Broader search without tsx file type issues
echo "=== SafeApiKit usage ==="
rg -n 'SafeApiKit' --type js --type ts 2>/dev/null || rg -n 'SafeApiKit'
echo ""
echo "=== Safe imports from `@safe-global` ==="
rg -n 'from.*@safe-global' --type js --type ts 2>/dev/null || rg -n 'from.*@safe-global'
echo ""
echo "=== `@ethereumjs/util` imports ==="
rg -n 'from.*@ethereumjs/util' --type js --type ts 2>/dev/null || rg -n 'from.*@ethereumjs/util'
echo ""
echo "=== ethereumjs-util imports ==="
rg -n 'from.*ethereumjs-util' --type js --type ts 2>/dev/null || rg -n 'from.*ethereumjs-util'Repository: cowprotocol/cowswap
Length of output: 5520
🏁 Script executed:
#!/bin/bash
# Check the purpose and scope of libs/wallet
echo "=== libs/wallet package.json metadata ==="
head -20 libs/wallet/package.json
echo ""
echo "=== libs/wallet directory structure ==="
find libs/wallet -maxdepth 2 -type f -name "*.ts" -o -name "*.js" | head -20Repository: cowprotocol/cowswap
Length of output: 725
🏁 Script executed:
#!/bin/bash
# Search more broadly for any Safe-related code
rg -n 'Safe' -i --max-count=30Repository: cowprotocol/cowswap
Length of output: 50377
🏁 Script executed:
#!/bin/bash
# Check if ethereumjs-util is a transitive dependency
echo "=== Check which package depends on ethereumjs-util ==="
rg -n "ethereumjs-util" libs/wallet/package.json libs/core/package.json package.json
echo ""
echo "=== Check lock file for ethereumjs-util dependency chain ==="
rg -B5 -A2 "^ ethereumjs-util@" pnpm-lock.yaml 2>/dev/null | head -50Repository: cowprotocol/cowswap
Length of output: 819
🏁 Script executed:
#!/bin/bash
# Check the TrezorConnector usage to confirm it's the only place `@ethereumjs/util` is used
echo "=== Verify TrezorConnector usage of `@ethereumjs/util` ==="
cat -n libs/wallet/src/web3-react/connectors/TrezorConnector/getAccountsList.ts | head -20Repository: cowprotocol/cowswap
Length of output: 964
Verify SafeApiKit v4 integration and remove unused ethereumjs-util dependency.
The upgrade from @safe-global/api-kit v1.x to v4.x is properly integrated across the codebase. Imports from the new @safe-global/types-kit (replacing safe-core-sdk-types) are used correctly throughout, including SafeMultisigTransactionResponse and MetaTransactionData.
However, ethereumjs-util v7.1.5 (line 55) is listed in dependencies but has no usages in the codebase. The package @ethereumjs/util v10.1.0 (line 40) is the active modern ESM replacement, used only in libs/wallet/src/web3-react/connectors/TrezorConnector/getAccountsList.ts. Remove the unused ethereumjs-util entry to clean up dependencies.
🤖 Prompt for AI Agents
In `@libs/wallet/package.json` around lines 40 - 45, Remove the unused legacy
dependency "ethereumjs-util" from package.json and keep the modern
"@ethereumjs/util" v10.1.0 in place; specifically delete the "ethereumjs-util"
entry, run the package manager to update lockfiles (npm/yarn/pnpm install), and
verify imports in
libs/wallet/src/web3-react/connectors/TrezorConnector/getAccountsList.ts still
reference "@ethereumjs/util" (not "ethereumjs-util") so nothing breaks.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
eslint.config.js (2)
240-271: Rule override may unintentionally drop root restrictions.This config block defines a new
@typescript-eslint/no-restricted-importsforapps/cowswap-frontend/**files. In ESLint flat config, this completely replaces (not merges with) the root-level restrictions defined at lines 125-159.As a result, for cowswap-frontend files, the following root restrictions will not apply:
ethers→ use@ethersproject/*styled-components→ usestyled-components/macro@1inch/permit-signed-approvals-utils→ use@cowprotocol/permit-utils@safe-global/api-kit→ use dynamic importTo preserve the root restrictions while adding frontend-specific ones, you need to merge the paths arrays explicitly.
🔧 Suggested fix to merge restrictions
// CoW Swap's rules { files: ['apps/cowswap-frontend/**/*.{ts,tsx,js,jsx}'], rules: { '@typescript-eslint/no-restricted-imports': [ 'error', { paths: [ + // Root restrictions (must be duplicated for flat config) + { + name: 'ethers', + message: "Please import from '@ethersproject/module' directly to support tree-shaking.", + }, + { + name: 'styled-components', + message: 'Please import from styled-components/macro.', + }, + { + name: '@1inch/permit-signed-approvals-utils', + message: 'Please import from `@cowprotocol/permit-utils`.', + allowTypeImports: true, + }, + { + name: '@safe-global/api-kit', + message: 'Please use dynamic import.', + allowTypeImports: true, + }, + // Frontend-specific restrictions { name: 'react-router', importNames: ['useNavigate'], message: "Please import useNavigate from our own common package instead: 'common/hooks/useNavigate'", }, { name: 'lottie-react', message: 'Please use dynamic import.', allowTypeImports: true, }, { name: 'framer-motion', message: 'Please use dynamic import.', allowTypeImports: true, }, ], patterns: [ { group: ['**/dist'], message: 'Do not import from dist/ - this is an implementation detail, and breaks tree-shaking.', }, { group: ['!styled-components/macro'], }, ], }, ], }, },Alternatively, consider extracting the common restrictions into a shared variable and spreading them into each config block to avoid duplication.
281-292: Same rule override concern applies here.This config for
apps/cowswap-frontend/src/common/**also defines its own@typescript-eslint/no-restricted-imports, which will replace both the root restrictions and the cowswap-frontend restrictions for files in the common directory.Files in
common/will lose restrictions onethers,styled-components,@1inch/*,@safe-global/api-kit,lottie-react,framer-motion, anduseNavigate.If this is intentional (only wanting the modules import restriction for common/), consider documenting it. Otherwise, merge the paths arrays as suggested for the frontend config.
🤖 Fix all issues with AI agents
In `@apps/widget-configurator/package.json`:
- Line 37: Update the pinned ethers dependency in package.json: change the exact
"ethers": "5.7.2" entry to either the latest v5 release "5.8.0" or use a caret
range like "ethers": "^5.7.2" so the package can receive patch updates; modify
the dependency string in apps/widget-configurator's package.json (the "ethers"
entry) accordingly and run npm/yarn install to update lockfiles.
| "@mui/icons-material": "^5.17.1", | ||
| "@mui/material": "^5.17.1", | ||
| "@web3modal/ethers5": "^4.1.9", | ||
| "ethers": "5.7.2", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check `@web3modal/ethers5` peer dependency requirements for ethers
npm view `@web3modal/ethers5`@4.1.9 peerDependencies --json 2>/dev/null | jq '.ethers // "not specified"'
# Check latest ethers v5.x version
npm view ethers versions --json 2>/dev/null | jq '[.[] | select(startswith("5."))] | .[-1]'Repository: cowprotocol/cowswap
Length of output: 87
Update ethers to the latest v5 version (5.8.0) or use caret to allow patch updates.
The version 5.7.2 is compatible with @web3modal/ethers5@4.1.9 (which requires >=4.1.0 <6.0.0), but it is outdated. The latest ethers v5 version is 5.8.0. Since you've pinned the version exactly without a caret, this dependency won't receive patch updates that may include security fixes or bug improvements. Consider updating to 5.8.0 or using ^5.7.2 to allow automatic patch updates.
🤖 Prompt for AI Agents
In `@apps/widget-configurator/package.json` at line 37, Update the pinned ethers
dependency in package.json: change the exact "ethers": "5.7.2" entry to either
the latest v5 release "5.8.0" or use a caret range like "ethers": "^5.7.2" so
the package can receive patch updates; modify the dependency string in
apps/widget-configurator's package.json (the "ethers" entry) accordingly and run
npm/yarn install to update lockfiles.
Summary
Bundle size optimization for swap.cow.fi (see grant proposal)
Results:
devmode should start fasterInitial loading size before/after
Before

After

Done
@safe-global/api-kit- dynamic import +@safe-global/**new versions (esm support)@1inch/permit-signed-approvals-utils- dynamic import + partial re-export (for better tree-shaking) + new version (esm support) + hardcode used constants@use-gesture/coreand@safe-global/safe-apps-sdk)bn.jslottie-react- dynamic importframer-motion- dynamic importOther
index-[hash].js->metamask-[hash].js)Todo
Caveats
@safe-global/**new versions have slightly different types (e.g. fornonce), there may be problems I couldn't catch (e.g. on the sdk side)To Test
rimraf node_modulesbeforeyarn installusageBackground
Optional: Give background information for changes you've made, that might be difficult to explain via comments
Summary by CodeRabbit
New Features
Bug Fixes
Chores / Refactor
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.