Skip to content

feat/PRO-3797/7702-onboarding#445

Merged
RanaBug merged 12 commits intostagingfrom
feat/PRO-3797/7702-onboarding
Nov 4, 2025
Merged

feat/PRO-3797/7702-onboarding#445
RanaBug merged 12 commits intostagingfrom
feat/PRO-3797/7702-onboarding

Conversation

@RanaBug
Copy link
Collaborator

@RanaBug RanaBug commented Oct 28, 2025

Description

  • EIP7702 onboarding modal

How Has This Been Tested?

  • Unit Tests and Manual Testing

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Summary by CodeRabbit

  • New Features

    • In-app EIP-7702 wallet upgrade flow: eligibility checks, gas estimation, modal UI, progress/status views and actionable Upgrade button.
    • Wallet-mode awareness and per-chain authorization integrated into transaction estimation/sending and provider selection.
    • Wallet-mode verification context/hook and an EIP-7702 info provider; error sanitization utility added.
  • Tests

    • Comprehensive unit tests for the upgrade UI and related components.
  • Chore

    • Transaction kit dependency bumped to v2.1.1.

@RanaBug RanaBug self-assigned this Oct 28, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 28, 2025

Walkthrough

Adds EIP‑7702 support: wallet‑mode verification, delegated‑EOA authorization checks, a new upgrade modal (UI, polling, gas estimation), provider/context and hooks, propagates authorization into estimate/send flows, updates WalletPortfolio slice, many component/test additions, and bumps @etherspot/transaction-kit to 2.1.1.

Changes

Cohort / File(s) Summary
Dependency
package.json
Updated @etherspot/transaction-kit from 2.0.3 to 2.1.1.
EIP‑7702 Modal & UI
src/components/EIP7702UpgradeModal/*
New modal and UI suite plus tests: EIP7702UpgradeModal.tsx, EIP7702UpgradeAction.tsx, EIP7702UpgradeDetails.tsx, EIP7702UpgradeProgressStep.tsx, EIP7702UpgradeStatus.tsx, EIP7702UpgradeStatusButton.tsx, EIP7702UpgradeStatusIcon.tsx, types.ts — lifecycle, polling, animations, status UI and associated tests.
State slice
src/apps/pillarx-app/reducer/WalletPortfolioSlice.ts
Added flags and reducers: isUpgradeWalletModalOpen, isEIP7702Eligible, hasCompletedEIP7702Upgrade with actions.
Hooks & Providers
src/hooks/*, src/providers/EIP7702Provider.tsx
New hooks: useWalletModeVerification.tsx, useEIP7702Upgrade.tsx, useEIP7702Info.tsx; new EIP7702Provider and exported EIP‑7702 info types.
Authorization util & helpers
src/utils/eip7702Authorization.ts, src/utils/upgrade.tsx, src/utils/common.ts
Added getEIP7702AuthorizationIfNeeded, OUR_EIP7702_IMPLEMENTATION_ADDRESS, UI config (STATUS_CONFIG, BUTTON_CONFIG, getters), and sanitizeError.
Send / Batch flows
src/components/BottomMenuModal/SendModal/SendModalBatchesTabView.tsx, .../SendModalTokensTabView.tsx
Injects EIP‑7702 authorization into estimate/send calls, passes authorization to kit APIs, adjusts userOpHash extraction to chainGroups[0].userOpHash, and adds delegatedEoa fee‑mode branching and chainId validation.
Pulse sell & gas
src/apps/pulse/components/Sell/PreviewSell.tsx, .../Sell.tsx, src/apps/pulse/hooks/useGasEstimation.ts
Fetches authorization for batch sends and gas estimation; adapts userOpHash handling and minor import reorder.
PillarX integration
src/apps/pillarx-app/index.tsx, src/apps/pillarx-app/components/WalletPortfolioButtons/WalletPortfolioButtons.tsx, src/apps/pillarx-app/components/PortfolioOverview/PortfolioOverview.tsx
Hooks upgrade modal into app render/store; adds Upgrade button conditioned on eligibility; hides dropdown in delegatedEoa wallet mode.
Authorized container
src/containers/Authorized.tsx
Creates temporary kit for verification, runs wallet‑mode verification, wraps app with EIP7702Provider, surfaces verification loading/errors.
WalletConnect service
src/services/walletConnect.ts
Branches signing flows for delegatedEoa vs modular, improves error handling and unknown-relayer event handling.
Tests & Mocks
src/components/EIP7702UpgradeModal/tests/*, src/apps/pulse/components/Sell/tests/PreviewSell.test.tsx, __mocks__/useTransactionKit.ts
New/updated tests and mocks: modal component tests; Pulse sell test mocks updated for getEIP7702AuthorizationIfNeeded, chainGroups userOpHash shape, and provider getWalletMode mock returning 'modular'.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App
    participant Kit as TransactionKit
    participant Chain
    participant Modal

    User->>App: login / app load
    App->>Kit: create temp kit for verification
    App->>Chain: query EOA code & balances per chain
    App->>App: derive walletMode & eip7702Info
    App->>App: useEIP7702Upgrade.checkOnLogin -> calculate gas & eligibility
    alt eligible and hasEnoughGas
        App->>Modal: open EIP7702UpgradeModal
    end

    User->>Modal: "Upgrade now"
    Modal->>Kit: delegateSmartAccountToEoa
    Kit->>Chain: submit delegation (userOp)
    Chain-->>Kit: userOpHash
    loop every 2s
        Modal->>Kit: getUserOperationStatus(userOpHash)
        Kit->>Chain: fetch status
        Kit-->>Modal: status update
    end
    Kit-->>Modal: status = completed
    Modal->>App: dispatch completion actions
Loading
sequenceDiagram
    participant User
    participant SendUI
    participant EIPAuth as EIP7702Auth
    participant Kit as TransactionKit
    participant Chain

    User->>SendUI: initiate send
    SendUI->>SendUI: determine wallet mode (provider/kit)
    alt delegatedEoa
        SendUI->>SendUI: force Native fee, disable gasless
    else modular
        SendUI->>SendUI: allow Gasless options
    end

    SendUI->>EIPAuth: getEIP7702AuthorizationIfNeeded(kit, chainId)
    EIPAuth->>Chain: read code at wallet address
    alt our implementation present
        EIPAuth-->>SendUI: null (no auth needed)
    else other/absent
        EIPAuth->>Kit: delegateSmartAccountToEoa(delegateImmediately=false)
        Kit-->>EIPAuth: authorization
        EIPAuth-->>SendUI: authorization
    end

    SendUI->>Kit: estimate/send (authorization?)
    Kit->>Chain: estimate/send
    Chain-->>Kit: userOpHash (chainGroups[0])
    Kit-->>SendUI: result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45–75 minutes

  • Files needing extra attention:
    • src/components/EIP7702UpgradeModal/EIP7702UpgradeModal.tsx (state machine, polling, timing/grace windows)
    • src/hooks/useWalletModeVerification.tsx (multi‑chain on‑chain reads and delegate extraction)
    • src/hooks/useEIP7702Upgrade.tsx (gas calculations, eligibility, modal coordination)
    • src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx and SendModalBatchesTabView.tsx (fee‑mode branching and authorization passing)
    • src/containers/Authorized.tsx (temp kit lifecycle and provider composition)

Possibly related PRs

Suggested reviewers

  • IAmKio
  • vignesha22

Poem

🐰 I hopped along the code-lined trail,
Found modals, polls, and gas to scale,
I checked each chain and fetched the key,
Now upgrades hum like springtime glee.
Hop on—EIP‑7702, let's be free! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat/PRO-3797/7702-onboarding' clearly identifies the main change: implementing EIP-7702 onboarding functionality, aligning with the PR's objective and the extensive modal implementation across multiple files.
Description check ✅ Passed The description provides a concise summary ('EIP7702 onboarding modal'), indicates testing was performed ('Unit Tests and Manual Testing'), and specifies the type of change (new feature and breaking change). However, it lacks detail on specific testing scope, test coverage, or affected systems.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/PRO-3797/7702-onboarding

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

❤️ Share

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

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Oct 28, 2025

Deploying x with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3f8aa18
Status: ✅  Deploy successful!
Preview URL: https://66f2bd15.x-e62.pages.dev
Branch Preview URL: https://feat-pro-3797-7702-onboardin.x-e62.pages.dev

View logs

@github-actions github-actions bot temporarily deployed to Preview (feat/PRO-3797/7702-onboarding) October 29, 2025 22:02 Inactive
@RanaBug RanaBug requested a review from IAmKio October 30, 2025 13:00
@RanaBug RanaBug marked this pull request as ready for review October 30, 2025 13:00
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: 7

🧹 Nitpick comments (3)
src/apps/the-exchange/index.tsx (1)

32-36: Consider adding defensive handling for unexpected wallet modes.

The conditional provider selection assumes walletMode is either 'modular' or falls through to the getWalletClient() path. If walletMode could be undefined or have unexpected values, consider adding validation.

If additional safety is desired, you could add:

  const { walletMode } = kit.getEtherspotProvider().getConfig();
+ if (!walletMode) {
+   console.warn('Wallet mode not configured, defaulting to wallet client provider');
+ }
  const provider =
    walletMode === 'modular'
      ? kit.getProvider()
      : kit.getEtherspotProvider().getWalletClient();
src/providers/EIP7702Provider.tsx (1)

1-1: Consider memoizing the context value instead of disabling the linting rule.

The inline object { eip7702Info } is recreated on every render. While this may not cause issues if the provider doesn't re-render frequently, memoizing the value follows React best practices and avoids the eslint-disable.

Apply this refactor:

-/* eslint-disable react/jsx-no-constructed-context-values */
-import React, { createContext } from 'react';
+import React, { createContext, useMemo } from 'react';

 // types
 import { EIP7702Info } from '../hooks/useWalletModeVerification';
 export const EIP7702Provider: React.FC<EIP7702ProviderProps> = ({
   eip7702Info,
   children,
 }) => {
+  const value = useMemo(() => ({ eip7702Info }), [eip7702Info]);
+
   return (
-    <EIP7702Context.Provider value={{ eip7702Info }}>
+    <EIP7702Context.Provider value={value}>
       {children}
     </EIP7702Context.Provider>
   );
 };

Also applies to: 22-25

src/components/EIP7702UpgradeModal/EIP7702UpgradeProgressStep.tsx (1)

39-41: Consider simplifying the line status conditional.

The ternary chain on line 40 is quite long and could be more readable.

  const getLineClasses = () => {
-    return `w-0.5 h-4 ml-2 ${lineStatus === 'completed' || lineStatus === 'upgrading' || lineStatus === 'failed' ? 'bg-[#8A77FF]' : 'bg-[#121116]'}`;
+    const isActive = ['completed', 'upgrading', 'failed'].includes(lineStatus);
+    return `w-0.5 h-4 ml-2 ${isActive ? 'bg-[#8A77FF]' : 'bg-[#121116]'}`;
  };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ebaf571 and ca67945.

⛔ Files ignored due to path filters (6)
  • package-lock.json is excluded by !**/package-lock.json
  • src/assets/images/confirmed-icon.svg is excluded by !**/*.svg
  • src/assets/images/failed-icon.svg is excluded by !**/*.svg
  • src/assets/images/pending.svg is excluded by !**/*.svg
  • src/assets/images/upgrade-diagonal-arrows.svg is excluded by !**/*.svg
  • src/assets/images/upgrade-green-logo.svg is excluded by !**/*.svg
📒 Files selected for processing (27)
  • package.json (1 hunks)
  • src/apps/pillarx-app/components/WalletPortfolioButtons/WalletPortfolioButtons.tsx (3 hunks)
  • src/apps/pillarx-app/index.tsx (4 hunks)
  • src/apps/pillarx-app/reducer/WalletPortfolioSlice.ts (4 hunks)
  • src/apps/pulse/components/Sell/PreviewSell.tsx (2 hunks)
  • src/apps/pulse/components/Sell/Sell.tsx (1 hunks)
  • src/apps/pulse/hooks/useGasEstimation.ts (2 hunks)
  • src/apps/the-exchange/index.tsx (1 hunks)
  • src/components/BottomMenuModal/SendModal/SendModalBatchesTabView.tsx (4 hunks)
  • src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx (13 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeAction.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeDetails.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeModal.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeProgressStep.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeStatus.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeStatusButton.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeStatusIcon.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/types.ts (1 hunks)
  • src/containers/Authorized.tsx (5 hunks)
  • src/hooks/useEIP7702Info.tsx (1 hunks)
  • src/hooks/useEIP7702Upgrade.tsx (1 hunks)
  • src/hooks/useWalletModeVerification.tsx (1 hunks)
  • src/providers/EIP7702Provider.tsx (1 hunks)
  • src/services/walletConnect.ts (4 hunks)
  • src/utils/common.ts (1 hunks)
  • src/utils/eip7702Authorization.ts (1 hunks)
  • src/utils/upgrade.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-20T09:14:16.888Z
Learnt from: RanaBug
PR: pillarwallet/x#374
File: src/apps/pillarx-app/index.tsx:12-12
Timestamp: 2025-08-20T09:14:16.888Z
Learning: In this codebase, Transaction Kit providers are set up at the container level (src/containers/Authorized.tsx), not at individual app component levels. App components like src/apps/pillarx-app/index.tsx are children that consume the context through the provider tree.

Applied to files:

  • src/providers/EIP7702Provider.tsx
  • src/apps/the-exchange/index.tsx
  • src/apps/pulse/hooks/useGasEstimation.ts
  • src/containers/Authorized.tsx
  • src/apps/pillarx-app/index.tsx
📚 Learning: 2025-09-09T12:40:15.629Z
Learnt from: RanaBug
PR: pillarwallet/x#391
File: src/apps/pulse/components/Sell/Sell.tsx:113-130
Timestamp: 2025-09-09T12:40:15.629Z
Learning: In the Pulse app Sell component, when a user changes/switches tokens, the input amount automatically resets to 0, which means liquidity validation state doesn't become stale when tokens change.

Applied to files:

  • src/apps/pulse/components/Sell/Sell.tsx
🧬 Code graph analysis (20)
src/hooks/useEIP7702Info.tsx (1)
src/providers/EIP7702Provider.tsx (1)
  • EIP7702Context (11-11)
src/components/EIP7702UpgradeModal/EIP7702UpgradeStatus.tsx (2)
src/components/EIP7702UpgradeModal/types.ts (1)
  • UpgradeStatus (1-6)
src/utils/upgrade.tsx (1)
  • getStatusConfig (103-105)
src/apps/pulse/components/Sell/PreviewSell.tsx (1)
src/utils/eip7702Authorization.ts (1)
  • getEIP7702AuthorizationIfNeeded (16-95)
src/components/EIP7702UpgradeModal/EIP7702UpgradeProgressStep.tsx (1)
src/components/EIP7702UpgradeModal/types.ts (1)
  • UpgradeStatus (1-6)
src/providers/EIP7702Provider.tsx (1)
src/hooks/useWalletModeVerification.tsx (1)
  • EIP7702Info (16-23)
src/components/EIP7702UpgradeModal/EIP7702UpgradeAction.tsx (1)
src/utils/number.tsx (1)
  • limitDigitsNumber (42-69)
src/components/EIP7702UpgradeModal/EIP7702UpgradeModal.tsx (5)
src/hooks/useTransactionDebugLogger.tsx (1)
  • useTransactionDebugLogger (1-15)
src/components/EIP7702UpgradeModal/types.ts (2)
  • UpgradeStatus (1-6)
  • UserOpUpgradeStatus (8-15)
src/hooks/useEIP7702Upgrade.tsx (1)
  • useEIP7702Upgrade (27-181)
src/services/userOpStatus.ts (1)
  • getUserOperationStatus (3-44)
src/apps/pillarx-app/reducer/WalletPortfolioSlice.ts (2)
  • setHasCompletedEIP7702Upgrade (143-145)
  • setIsEIP7702Eligible (140-142)
src/components/BottomMenuModal/SendModal/SendModalBatchesTabView.tsx (1)
src/utils/eip7702Authorization.ts (1)
  • getEIP7702AuthorizationIfNeeded (16-95)
src/components/EIP7702UpgradeModal/EIP7702UpgradeDetails.tsx (2)
src/components/EIP7702UpgradeModal/types.ts (1)
  • UpgradeStatus (1-6)
src/utils/upgrade.tsx (1)
  • formatStepTimestamp (117-132)
src/apps/pillarx-app/components/WalletPortfolioButtons/WalletPortfolioButtons.tsx (1)
src/hooks/useEIP7702Upgrade.tsx (1)
  • useEIP7702Upgrade (27-181)
src/hooks/useEIP7702Upgrade.tsx (3)
src/hooks/useTransactionDebugLogger.tsx (1)
  • useTransactionDebugLogger (1-15)
src/hooks/useEIP7702Info.tsx (1)
  • useEIP7702Info (6-12)
src/apps/pillarx-app/reducer/WalletPortfolioSlice.ts (2)
  • setIsEIP7702Eligible (140-142)
  • setIsUpgradeWalletModalOpen (137-139)
src/components/EIP7702UpgradeModal/EIP7702UpgradeStatusButton.tsx (2)
src/components/EIP7702UpgradeModal/types.ts (1)
  • UpgradeStatus (1-6)
src/utils/upgrade.tsx (1)
  • getButtonConfig (110-112)
src/services/walletConnect.ts (1)
src/utils/walletConnect.ts (4)
  • PERSONAL_SIGN (4-4)
  • ETH_SIGN_TYPED_DATA (8-8)
  • ETH_SIGN_TYPED_DATA_V4 (9-9)
  • ETH_SEND_TX (6-6)
src/apps/pulse/hooks/useGasEstimation.ts (1)
src/utils/eip7702Authorization.ts (1)
  • getEIP7702AuthorizationIfNeeded (16-95)
src/containers/Authorized.tsx (3)
src/hooks/useWalletModeVerification.tsx (1)
  • useWalletModeVerification (37-191)
src/providers/EtherspotTransactionKitProvider.tsx (1)
  • EtherspotTransactionKitProvider (30-73)
src/providers/EIP7702Provider.tsx (1)
  • EIP7702Provider (18-27)
src/utils/upgrade.tsx (2)
src/apps/pulse/types/types.ts (1)
  • ButtonConfig (61-66)
src/components/EIP7702UpgradeModal/types.ts (1)
  • UpgradeStatus (1-6)
src/hooks/useWalletModeVerification.tsx (2)
src/utils/blockchain.ts (1)
  • visibleChains (161-163)
src/utils/common.ts (1)
  • sanitizeError (83-110)
src/components/EIP7702UpgradeModal/EIP7702UpgradeStatusIcon.tsx (2)
src/components/EIP7702UpgradeModal/types.ts (1)
  • UpgradeStatus (1-6)
src/utils/upgrade.tsx (1)
  • getStatusConfig (103-105)
src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx (1)
src/utils/eip7702Authorization.ts (1)
  • getEIP7702AuthorizationIfNeeded (16-95)
src/apps/pillarx-app/index.tsx (3)
src/apps/pillarx-app/hooks/useReducerHooks.tsx (2)
  • useAppSelector (6-6)
  • useAppDispatch (5-5)
src/hooks/useEIP7702Upgrade.tsx (1)
  • useEIP7702Upgrade (27-181)
src/apps/pillarx-app/reducer/WalletPortfolioSlice.ts (1)
  • setIsUpgradeWalletModalOpen (137-139)
🪛 Biome (2.1.2)
src/components/EIP7702UpgradeModal/EIP7702UpgradeAction.tsx

[error] 1-1: Do not shadow the global "isNaN" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🔇 Additional comments (19)
src/utils/common.ts (1)

77-110: LGTM! Well-structured error sanitization utility.

The sanitizeError function properly handles multiple error types and safely redacts sensitive data using regex escaping. The try/catch around JSON.stringify prevents potential circular reference errors.

src/apps/pulse/components/Sell/Sell.tsx (1)

23-29: LGTM! Import reorganization only.

The import statements have been reorganized to include MobulaChainNames and getChainId from the constants module. No logic changes.

src/hooks/useEIP7702Info.tsx (1)

1-12: LGTM! Standard context hook pattern.

The hook correctly throws an error when EIP7702Context is not provided, ensuring it's used within the proper provider tree.

src/apps/pillarx-app/components/WalletPortfolioButtons/WalletPortfolioButtons.tsx (2)

5-6: LGTM! Clean integration of EIP-7702 upgrade hook.

The useEIP7702Upgrade hook is properly imported and consumed to provide eligibility state and upgrade action.

Also applies to: 21-21


49-60: LGTM! Upgrade button follows existing patterns.

The Upgrade button is conditionally rendered based on eligibility and maintains consistent styling with the existing Receive button. The upward arrow (via rotate-180) effectively communicates the "upgrade" action.

src/apps/pillarx-app/reducer/WalletPortfolioSlice.ts (2)

35-37: LGTM! Clean addition of EIP-7702 upgrade state.

The three new state fields are properly typed and initialized, following the existing pattern in the slice.

Also applies to: 62-64


137-145: LGTM! Standard Redux Toolkit reducer pattern.

The new reducers and exported actions follow Redux Toolkit best practices with proper typing via PayloadAction<boolean>.

Also applies to: 168-170

package.json (1)

25-25: Package version verified as valid with no known security advisories.

The @etherspot/transaction-kit@2.1.1 package version exists on the npm registry and no security vulnerabilities are currently recorded for this package. The upgrade is safe to proceed with.

src/components/EIP7702UpgradeModal/EIP7702UpgradeStatus.tsx (1)

1-35: LGTM!

The component is well-structured with proper memoization and clean composition. The use of getStatusConfig centralizes status configuration logic effectively.

src/apps/pulse/hooks/useGasEstimation.ts (1)

94-101: LGTM!

The EIP-7702 authorization integration is properly implemented. Authorization is fetched after transaction building and correctly passed to the estimation call with appropriate fallback handling.

src/apps/pulse/components/Sell/PreviewSell.tsx (2)

373-380: LGTM!

The authorization integration is consistent with the pattern used in useGasEstimation.ts and properly handles the EIP-7702 flow.


384-386: Comment mentions PillarX but this is in Pulse app.

The comment references PillarX batching behavior, but this file is in the Pulse app (src/apps/pulse/...). While the batching logic may be shared, the comment could be misleading.

Consider updating the comment:

-          // In PillarX we only batch transactions per chainId, this is why sendBatch should only
+          // We only batch transactions per chainId, this is why sendBatch should only
           // have one chainGroup per batch

Additionally, the access to chainGroups[0] assumes the array exists and has at least one element. Consider adding an optional chaining or validation:

-          const userOpHash = sentBatch?.chainGroups?.[0]?.userOpHash;
+          const userOpHash = sentBatch?.chainGroups?.[0]?.userOpHash;

Actually, optional chaining is already present, so the access is safe. The comment fix is the main suggestion.

Likely an incorrect or invalid review comment.

src/components/EIP7702UpgradeModal/types.ts (1)

1-15: LGTM!

The type definitions are clear and comprehensive, covering the complete lifecycle of the upgrade flow from ready to completed/failed states.

src/components/EIP7702UpgradeModal/EIP7702UpgradeDetails.tsx (2)

32-57: LGTM!

The step status calculation logic correctly maps the overall upgrade status to individual step states, supporting a clear linear progression through the upgrade flow.


60-143: LGTM!

The timestamp formatting logic and button behavior are well-designed. Timestamps are appropriately shown only for completed intermediate steps, and the "Done" button correctly handles both closing the details view and the entire modal based on the upgrade state.

src/components/EIP7702UpgradeModal/EIP7702UpgradeProgressStep.tsx (1)

54-127: LGTM!

The timestamp display logic and responsive behavior are well-implemented. The component appropriately shows full timestamps on larger screens and time-only on smaller screens.

src/components/BottomMenuModal/SendModal/SendModalBatchesTabView.tsx (2)

169-254: LGTM!

The EIP-7702 authorization integration is consistent with the patterns used in other components. Authorization is properly fetched once and reused for both estimation and sending operations.


294-296: LGTM!

The comment accurately describes the batching behavior and the userOpHash extraction is safely implemented with optional chaining.

src/components/EIP7702UpgradeModal/EIP7702UpgradeAction.tsx (1)

38-136: LGTM!

The component is well-structured with appropriate loading states, proper button disabled states, and clear visual feedback for gas checking and insufficient gas scenarios.

Comment on lines +180 to +193
// Check if user is eligible for EIP-7702 upgrade (when walletAddress loads on login)
const handleCheckEligibility = useCallback(() => {
if (walletAddress) {
checkOnLogin();
}
}, [walletAddress, checkOnLogin]);

useEffect(() => {
handleCheckEligibility();
}, [handleCheckEligibility]);

const handleCloseModal = () => {
dispatch(setIsUpgradeWalletModalOpen(false));
};
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 30, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Prevent modal eligibility check from wiping upgrade gas data

Because the effect depends on handleCheckEligibility, it fires every time checkOnLogin changes identity (e.g., whenever isUpgradeWalletModalOpen flips inside useEIP7702Upgrade). That re-enters checkOnLogin(), which immediately runs checkEligibilityAndShowModal, hits setGasUpgradeInfo(undefined), and then returns early because the modal is already open. The modal stays visible but its gas info is cleared, so users lose the freshly fetched upgrade cost each time the modal opens. Apply this diff to guard the effect on wallet-address changes only:

-  const handleCheckEligibility = useCallback(() => {
-    if (walletAddress) {
-      checkOnLogin();
-    }
-  }, [walletAddress, checkOnLogin]);
-
-  useEffect(() => {
-    handleCheckEligibility();
-  }, [handleCheckEligibility]);
+  const lastCheckedWalletRef = useRef<string | null>(null);
+
+  useEffect(() => {
+    if (!walletAddress || lastCheckedWalletRef.current === walletAddress) {
+      return;
+    }
+
+    lastCheckedWalletRef.current = walletAddress;
+    checkOnLogin();
+  }, [walletAddress, checkOnLogin]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Check if user is eligible for EIP-7702 upgrade (when walletAddress loads on login)
const handleCheckEligibility = useCallback(() => {
if (walletAddress) {
checkOnLogin();
}
}, [walletAddress, checkOnLogin]);
useEffect(() => {
handleCheckEligibility();
}, [handleCheckEligibility]);
const handleCloseModal = () => {
dispatch(setIsUpgradeWalletModalOpen(false));
};
// Check if user is eligible for EIP-7702 upgrade (when walletAddress loads on login)
const lastCheckedWalletRef = useRef<string | null>(null);
useEffect(() => {
if (!walletAddress || lastCheckedWalletRef.current === walletAddress) {
return;
}
lastCheckedWalletRef.current = walletAddress;
checkOnLogin();
}, [walletAddress, checkOnLogin]);
const handleCloseModal = () => {
dispatch(setIsUpgradeWalletModalOpen(false));
};
🤖 Prompt for AI Agents
In src/apps/pillarx-app/index.tsx around lines 180–193, the useEffect currently
depends on handleCheckEligibility which causes checkOnLogin to rerun whenever
checkOnLogin identity changes (e.g. when isUpgradeWalletModalOpen flips),
clearing gas info; change the effect so it only watches walletAddress: replace
the effect dependency with [walletAddress] and inside the effect call
checkOnLogin() only when walletAddress is truthy, ensuring checkOnLogin is not
triggered by modal state changes and thus preventing
setGasUpgradeInfo(undefined) from wiping the fetched gas data.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Tested behaviour and how it is works as well as suggestion

Copy link
Contributor

Choose a reason for hiding this comment

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

@RanaBug, thank you for testing both the current behavior and the suggested fix! I'm glad to hear the solution works as expected. The ref-based approach will ensure the eligibility check only runs when the wallet address actually changes, preventing the gas data from being cleared unnecessarily when the modal state updates.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

Comment on lines +1387 to +1396
const authorization = await getEIP7702AuthorizationIfNeeded(
kit,
chainIdToUse
);

// Estimate (no paymasterDetails)
transactionDebugLog('Estimating single payload transaction');
const estimated = await kit.estimate();
const estimated = await kit.estimate({
authorization: authorization || undefined,
});
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 30, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Provide a fallback chainId for single-transaction payloads

Here chainIdToUse comes straight from payload.transaction. That field is optional in our SendModalData (the rest of this file already falls back to etherspotDefaultChainId when it’s missing), so passing undefined into getEIP7702AuthorizationIfNeeded makes delegateSmartAccountToEoa throw and the WalletConnect flow fails. Please default chainIdToUse to something like payloadTx?.chainId ?? etherspotDefaultChainId (and use the same value for the authorization call) before invoking the helper.

🤖 Prompt for AI Agents
In src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx around
lines 1387 to 1396, the code passes chainIdToUse directly from
payload.transaction (which can be undefined) into
getEIP7702AuthorizationIfNeeded causing delegateSmartAccountToEoa to throw;
ensure you compute a fallback first (e.g. const chainIdToUse =
payloadTx?.chainId ?? etherspotDefaultChainId) and then pass that resolved value
into getEIP7702AuthorizationIfNeeded (and use the same resolved chainId for any
subsequent calls like kit.estimate) so undefined is never forwarded.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed (see comment above)

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the current state of the chainIdToUse assignment in the PR branch
# Look for the line where chainIdToUse is defined in the payload transaction section

echo "=== Checking chainIdToUse assignment around line 1375 ==="
sed -n '1370,1395p' src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx | grep -A 5 -B 5 "chainIdToUse"

echo ""
echo "=== Checking if etherspotDefaultChainId is used as fallback ==="
sed -n '1370,1395p' src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx | grep "etherspotDefaultChainId"

Length of output: 908


🏁 Script executed:

#!/bin/bash
# Check recent commits to see if there's a fix that might not be in the current state
git log --oneline -10 --all -- src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx

echo ""
echo "=== Checking the most recent commit for this file ==="
git log -1 --stat -- src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx

Length of output: 937


🏁 Script executed:

#!/bin/bash
# Check the specific commit that mentions "resolution of single transaction chainId"
echo "=== Checking commit 2bb7eed for the chainId fix ==="
git show 2bb7eed:src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx | sed -n '1370,1395p' | grep -A 5 -B 5 "chainIdToUse"

echo ""
echo "=== Checking current HEAD for chainIdToUse assignment ==="
git show HEAD:src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx | sed -n '1370,1395p' | grep -A 3 -B 3 "chainIdToUse"

Length of output: 651


🏁 Script executed:

#!/bin/bash
# Check a broader range around the payload transaction section
echo "=== Looking at lines 1350-1410 to see full payload transaction section ==="
sed -n '1350,1410p' src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx

echo ""
echo "=== Searching for all uses of etherspotDefaultChainId in payload section ==="
sed -n '1300,1500p' src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx | grep -n "etherspotDefaultChainId"

Length of output: 2201


@RanaBug, thanks for the update! However, I've checked the current code on the PR branch and the fix doesn't appear to be applied yet.

Here's what I'm seeing at line 1375:

const chainIdToUse = payloadTx?.chainId;

This chainIdToUse can still be undefined because payloadTx?.chainId is optional. This undefined value is then passed to:

  1. kit.transaction({ chainId: chainIdToUse, ...}) on line 1377
  2. getEIP7702AuthorizationIfNeeded(kit, chainIdToUse) on line 1387

The needed fix:

const chainIdToUse = payloadTx?.chainId ?? etherspotDefaultChainId;

This ensures chainIdToUse always has a valid number value before being passed to the authorization helper and kit.transaction. The same pattern is already used elsewhere in this file (e.g., line 1198 for regular sends and line 1912 for batch adds).

Could you please apply this fallback? Let me know if you've already pushed this change and I'm looking at an outdated version! 🙏

Comment on lines +63 to +77
useEffect(() => {
if (provider && chainId) {
const tempKitConfig = {
provider,
chainId,
privateKey,
bundlerApiKey: import.meta.env.VITE_ETHERSPOT_BUNDLER_API_KEY,
walletMode: 'modular' as const, // Always start with modular for verification
} as unknown as EtherspotTransactionKitConfig;

const kit = new EtherspotTransactionKit(tempKitConfig);
setTempKit(kit);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [provider, privateKey]);
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 30, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Recreate the temp kit when chainId changes

useEffect depends only on provider and privateKey, yet its body also reads chainId. When the user switches networks the hook never reruns, so tempKit stays bound to the previous chain and useWalletModeVerification continues working with stale data. That leaves walletMode/eip7702Info incorrect and can block delegated-EOA flows on chain switches. Please add chainId to the dependency list (and clear the temp kit when either input becomes falsy) so the verification kit is rebuilt for the new chain.

🤖 Prompt for AI Agents
In src/containers/Authorized.tsx around lines 63 to 77, the useEffect currently
lists [provider, privateKey] but also reads chainId, so it fails to recreate the
tempKit when the user switches networks; update the effect to include chainId in
the dependency array and ensure that when any of provider, chainId, or
privateKey are falsy you clear tempKit (setTempKit(undefined)) instead of
creating it, otherwise build the EtherspotTransactionKit with the provider,
chainId, privateKey, bundlerApiKey and walletMode as before.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is on purpose that we do not include the chainId in the dependency list, this is because this effect should only run if the private key or provider changes. Indeed this useEffect triggers a tempkit that is used only to do some checks on all supported chains regardless of the chosen chainId.

Copy link
Contributor

Choose a reason for hiding this comment

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

@RanaBug, thank you for the clarification! I understand now—since useWalletModeVerification performs checks across all supported chains internally, the chainId passed to tempKit is only used as an initial configuration and doesn't affect the verification results. There's no need to recreate the kit when the user switches networks. I've noted this design decision for future reviews.

🐰✨


✏️ Learnings added
Learnt from: RanaBug
Repo: pillarwallet/x PR: 445
File: src/containers/Authorized.tsx:63-77
Timestamp: 2025-11-04T14:34:00.341Z
Learning: In src/containers/Authorized.tsx, the tempKit useEffect intentionally excludes chainId from its dependency array because the kit is used by useWalletModeVerification to check wallet mode across all supported chains, regardless of the currently selected chainId. The chainId parameter is only used for initial kit configuration and does not affect the multi-chain verification results.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: RanaBug
Repo: pillarwallet/x PR: 374
File: src/apps/pillarx-app/index.tsx:12-12
Timestamp: 2025-08-20T09:14:16.888Z
Learning: In this codebase, Transaction Kit providers are set up at the container level (src/containers/Authorized.tsx), not at individual app component levels. App components like src/apps/pillarx-app/index.tsx are children that consume the context through the provider tree.

Learnt from: RanaBug
Repo: pillarwallet/x PR: 275
File: src/apps/the-exchange/components/DropdownTokensList/DropdownTokenList.tsx:180-195
Timestamp: 2025-03-28T09:22:22.712Z
Learning: In the Exchange app, `swapTokenList` and `receiveTokenList` are derived from `searchTokenResult` when search is active, so including `searchToken` in the useEffect dependency array that uses these lists would be redundant as the lists will update when search results change.

Learnt from: RanaBug
Repo: pillarwallet/x PR: 320
File: src/components/BottomMenuModal/HistoryModal/TransactionInfo.tsx:177-182
Timestamp: 2025-05-28T14:30:02.702Z
Learning: In the transaction history tracking feature, chain ID validation is performed earlier in the flow before the values reach the TransactionInfo component, so additional validation at the display level is not needed.

@github-actions github-actions bot requested a deployment to Preview (feat/PRO-3797/7702-onboarding) October 30, 2025 17:04 Abandoned
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: 7

🧹 Nitpick comments (11)
src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeAction.test.tsx (4)

40-45: Consider the value of snapshot testing.

Snapshot tests can become brittle and may not catch meaningful regressions if not carefully reviewed during updates. Consider whether integration or specific assertion-based tests provide better value for this component.


84-85: Fragile CSS selector for checkmark verification.

The selector [class*="bg-"] is overly broad and matches any element with "bg-" in its class name, which could include backgrounds, borders, or unrelated styling. Consider using data-testid attributes on checkmark icons or more specific ARIA roles for reliable verification.

Apply this approach:

-      const checkIcons = container.querySelectorAll('[class*="bg-"]');
-      expect(checkIcons.length).toBeGreaterThanOrEqual(3);
+      const checkIcons = container.querySelectorAll('[data-testid="benefit-checkmark"]');
+      expect(checkIcons).toHaveLength(3);

121-126: Potential duplicate test.

This test appears to duplicate the assertion at lines 106-112, which already verifies that the button is disabled when hasEnoughGas={false}.


204-220: Tests tightly coupled to specific color values.

Using CSS selectors like .bg-\\[\\#8A77FF\\] tightly couples tests to exact hex colors. Theme or design updates will break these tests even if the component functions correctly. Consider testing the enabled/disabled state through accessibility attributes or behavior instead of visual styling.

   it('applies active button styles when enabled', () => {
-    const { container } = render(<EIP7702UpgradeAction {...baseProps} />);
+    render(<EIP7702UpgradeAction {...baseProps} />);

-    const button = container.querySelector('.bg-\\[\\#8A77FF\\]');
-    expect(button).toBeInTheDocument();
+    const button = screen.getByText('Upgrade now').closest('button');
+    expect(button).not.toBeDisabled();
+    expect(button).toHaveAttribute('aria-disabled', 'false');
   });
src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusButton.test.tsx (2)

88-102: Consider consolidating duplicate tests for upgrading and submitted statuses.

Both tests check identical behavior since the mocked getButtonConfig returns the same default configuration for upgrading and submitted statuses. Unless these statuses have distinct UI behaviors in the actual component, consider using a parameterized test or removing one of them to reduce maintenance overhead.

Example using it.each:

-    it('renders with upgrading status', () => {
-      render(<EIP7702UpgradeStatusButton {...baseProps} status="upgrading" />);
-
-      expect(screen.getByTestId('animated-button')).toBeInTheDocument();
-      expect(screen.getByText('View Details')).toBeInTheDocument();
-      expect(screen.getByTestId('tail-spin')).toBeInTheDocument();
-    });
-
-    it('renders with submitted status', () => {
-      render(<EIP7702UpgradeStatusButton {...baseProps} status="submitted" />);
-
-      expect(screen.getByTestId('animated-button')).toBeInTheDocument();
-      expect(screen.getByText('View Details')).toBeInTheDocument();
-      expect(screen.getByTestId('tail-spin')).toBeInTheDocument();
-    });
+    it.each(['upgrading', 'submitted'] as const)(
+      'renders with %s status showing loading state',
+      (status) => {
+        render(<EIP7702UpgradeStatusButton {...baseProps} status={status} />);
+
+        expect(screen.getByTestId('animated-button')).toBeInTheDocument();
+        expect(screen.getByText('View Details')).toBeInTheDocument();
+        expect(screen.getByTestId('tail-spin')).toBeInTheDocument();
+      }
+    );

161-165: Remove unnecessary negative test.

This test verifies that onClick is not called when the button is not clicked, which is self-evident and adds no coverage value. The test on lines 152-159 already confirms the onClick behavior works correctly.

Apply this diff to remove the unnecessary test:

-    it('does not call onClick when button is not clicked', () => {
-      render(<EIP7702UpgradeStatusButton {...baseProps} />);
-
-      expect(baseProps.onClick).not.toHaveBeenCalled();
-    });
src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusIcon.test.tsx (3)

70-96: Consider using test.each to reduce duplication.

The rendering tests follow an identical pattern across four statuses. While the current approach is clear, you could make it more maintainable with parameterized tests.

Example refactor:

-    it('renders with upgrading status', () => {
-      render(<EIP7702UpgradeStatusIcon status="upgrading" />);
-
-      expect(screen.getByTestId('animated-div')).toBeInTheDocument();
-      expect(screen.getByAltText('upgrading')).toBeInTheDocument();
-    });
-
-    it('renders with submitted status', () => {
-      render(<EIP7702UpgradeStatusIcon status="submitted" />);
-
-      expect(screen.getByTestId('animated-div')).toBeInTheDocument();
-      expect(screen.getByAltText('submitted')).toBeInTheDocument();
-    });
-
-    it('renders with completed status', () => {
-      render(<EIP7702UpgradeStatusIcon status="completed" />);
-
-      expect(screen.getByTestId('animated-div')).toBeInTheDocument();
-      expect(screen.getByAltText('completed')).toBeInTheDocument();
-    });
-
-    it('renders with failed status', () => {
-      render(<EIP7702UpgradeStatusIcon status="failed" />);
-
-      expect(screen.getByTestId('animated-div')).toBeInTheDocument();
-      expect(screen.getByAltText('failed')).toBeInTheDocument();
-    });
+    it.each(['upgrading', 'submitted', 'completed', 'failed'] as const)(
+      'renders with %s status',
+      (status) => {
+        render(<EIP7702UpgradeStatusIcon status={status} />);
+
+        expect(screen.getByTestId('animated-div')).toBeInTheDocument();
+        expect(screen.getByAltText(status)).toBeInTheDocument();
+      }
+    );

100-134: Consider using Testing Library queries instead of querySelector.

While container.querySelector('img') works, Testing Library's screen.getByRole('img') is more idiomatic and provides better error messages.

Example for one test:

     it('shows confirmed icon for completed status', () => {
-      const { container } = render(
+      render(
         <EIP7702UpgradeStatusIcon status="completed" />
       );
 
-      const img = container.querySelector('img');
-      expect(img?.getAttribute('alt')).toBe('completed');
+      expect(screen.getByRole('img')).toHaveAttribute('alt', 'completed');
     });

160-162: The act() wrapper is unnecessary here.

React Testing Library automatically wraps state updates in act(), so explicitly wrapping a synchronous rerender call is redundant. While not harmful, it adds visual noise.

-      act(() => {
-        rerender(<EIP7702UpgradeStatusIcon status="completed" />);
-      });
+      rerender(<EIP7702UpgradeStatusIcon status="completed" />);
src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeModal.test.tsx (2)

175-184: Replace tautological assertion with a real upgrade verification

This test currently ends with expect(true).toBe(true), so it never fails even if the upgrade button stops wiring through handleUpgradeClick. Please stub the hook with a dedicated handleUpgradeClick mock (e.g. via vi.mocked(useEIP7702Upgrade).mockReturnValueOnce({ …handleUpgradeClick })), click the button, and assert that the mock was invoked. That keeps the test meaningful and surfaces regressions in the upgrade trigger path.


191-209: Keep hook stubs isolated per test

Using .mockReturnValue here mutates the global useEIP7702Upgrade mock, and vi.clearAllMocks() doesn’t restore implementations. Subsequent tests therefore inherit this altered return shape, which hides ordering bugs. Prefer .mockReturnValueOnce(...) (or re-seeding the default implementation in beforeEach / calling vi.resetAllMocks()) so every test runs with the expected hook state in isolation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca67945 and 9864eb2.

⛔ Files ignored due to path filters (8)
  • package-lock.json is excluded by !**/package-lock.json
  • src/components/EIP7702UpgradeModal/tests/__snapshots__/EIP7702UpgradeAction.test.tsx.snap is excluded by !**/*.snap
  • src/components/EIP7702UpgradeModal/tests/__snapshots__/EIP7702UpgradeDetails.test.tsx.snap is excluded by !**/*.snap
  • src/components/EIP7702UpgradeModal/tests/__snapshots__/EIP7702UpgradeModal.test.tsx.snap is excluded by !**/*.snap
  • src/components/EIP7702UpgradeModal/tests/__snapshots__/EIP7702UpgradeProgressStep.test.tsx.snap is excluded by !**/*.snap
  • src/components/EIP7702UpgradeModal/tests/__snapshots__/EIP7702UpgradeStatus.test.tsx.snap is excluded by !**/*.snap
  • src/components/EIP7702UpgradeModal/tests/__snapshots__/EIP7702UpgradeStatusButton.test.tsx.snap is excluded by !**/*.snap
  • src/components/EIP7702UpgradeModal/tests/__snapshots__/EIP7702UpgradeStatusIcon.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (10)
  • package.json (1 hunks)
  • src/apps/pulse/components/Sell/tests/PreviewSell.test.tsx (2 hunks)
  • src/apps/the-exchange/index.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeDetails.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeAction.test.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeDetails.test.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeModal.test.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeProgressStep.test.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusButton.test.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusIcon.test.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/apps/the-exchange/index.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeModal.test.tsx (1)
src/hooks/useEIP7702Upgrade.tsx (1)
  • useEIP7702Upgrade (27-181)
src/components/EIP7702UpgradeModal/EIP7702UpgradeDetails.tsx (2)
src/components/EIP7702UpgradeModal/types.ts (1)
  • UpgradeStatus (1-6)
src/utils/upgrade.tsx (1)
  • formatStepTimestamp (117-132)
⏰ 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: lint
  • GitHub Check: unit-tests
🔇 Additional comments (10)
src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeAction.test.tsx (4)

1-32: Test setup looks good.

The mocks and base props are well-structured and provide a solid foundation for the test suite.


148-155: Verify disabled button click behavior.

Browsers typically don't fire click events on disabled buttons, but React Testing Library's fireEvent may artificially trigger events on disabled elements. This test might pass regardless of whether proper event handling is implemented. Consider using userEvent.click() from @testing-library/user-event, which more accurately simulates real user behavior and respects disabled states.

+import userEvent from '@testing-library/user-event';

   it('does not call handleUpgrade when button is disabled', () => {
     render(<EIP7702UpgradeAction {...baseProps} hasEnoughGas={false} />);

     const button = screen.getByText('Not enough gas');
-    fireEvent.click(button);
+    userEvent.click(button);

     expect(baseProps.handleUpgrade).not.toHaveBeenCalled();
   });

158-187: Edge cases are well covered.

The tests appropriately verify handling of missing, invalid, and empty gas fee estimates, ensuring the UI gracefully degrades.


189-202: Good defensive testing.

Testing with minimal required props ensures the component handles missing optional props gracefully.

package.json (1)

25-25: Verify that @etherspot/transaction-kit 2.1.1 is installable and does not conflict with known vulnerabilities.

The package-lock.json references v2.1.1 with a valid npm registry URL and integrity hash, but web search found only v2.0.3 publicly available. The codebase's audit-report.json also flags @etherspot/transaction-kit with a moderate severity vulnerability requiring a semver-major fix. Confirm this version bump is intentional, that v2.1.1 is genuinely available for installation, and that it addresses (or is unaffected by) the documented vulnerabilities.

src/apps/pulse/components/Sell/tests/PreviewSell.test.tsx (2)

66-70: No action required — PreviewSell already correctly handles the nested chainGroups structure.

The component correctly extracts userOpHash from the nested structure using optional chaining (chainGroups?.[0]?.userOpHash) at line 369 of PreviewSell.tsx, which matches the test data format and includes proper guards before usage.


47-49: No changes needed – mock is correct and necessary.

The getWalletMode mock is essential because the getEIP7702AuthorizationIfNeeded utility checks wallet mode early and returns undefined if it's not 'delegatedEoa'. PreviewSell invokes this utility in executeSellDirectly(), so the mock must provide this method.

The hardcoded 'modular' value is appropriate here: the PreviewSell component itself contains no wallet-mode-conditional logic. It passes the authorization result to kit.sendBatches() regardless of mode. If testing different wallet mode behaviors for EIP-7702 authorization is desired, that belongs in dedicated tests for getEIP7702AuthorizationIfNeeded, not in the PreviewSell component test.

src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusButton.test.tsx (1)

64-67: The useSpring mock is correct and matches actual component usage.

The component destructures useSpring into [springs, api], uses springs as a style object at line 99, and calls api.set() and api.start() at lines 45-50. The mock returns exactly this structure with appropriate implementations for the actual methods used in the component.

src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusIcon.test.tsx (2)

1-7: LGTM!

Standard test setup with appropriate imports and component under test.


34-59: LGTM!

SVG asset mocks and @react-spring/web mock are properly structured for testing. The useSpring tuple return matches the API form when used with a function argument.

Comment on lines 41 to 47
vi.mock('../../assets/images/confirmed-icon.svg', () => ({
default: 'confirmed-icon.svg',
}));

vi.mock('../../assets/images/failed-icon.svg', () => ({
default: 'failed-icon.svg',
}));
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 30, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the SVG asset mock paths.

The mock paths for SVG assets use '../../assets/images/', which would resolve to src/components/assets/images/. Typically, assets are located at src/assets/. If so, the correct paths should be '../../../assets/images/confirmed-icon.svg' and '../../../assets/images/failed-icon.svg'.

Run this script to verify the asset locations:


🏁 Script executed:

#!/bin/bash
# Find the actual location of the icon files
fd -t f "confirmed-icon.svg" -e svg
fd -t f "failed-icon.svg" -e svg

Length of output: 149



---

🏁 Script executed:

```shell
#!/bin/bash
# Find the component file and check its imports
fd -t f "EIP7702UpgradeStatusButton" --type tsx --type ts
# Also look for what files import from assets/images
rg -n "confirmed-icon|failed-icon" --type tsx --type ts -C2

Length of output: 198



---

🏁 Script executed:

```shell
#!/bin/bash
# Find EIP7702UpgradeStatusButton component file
fd "EIP7702UpgradeStatusButton" -e tsx -e ts

# Search for imports of these icons across the codebase
rg "confirmed-icon\.svg|failed-icon\.svg" -n -C1

Length of output: 4295


Update mock paths and component imports to correct asset location.

The SVG imports in both the component (src/components/EIP7702UpgradeModal/EIP7702UpgradeStatusButton.tsx, lines 6-7) and the test file use ../../assets/images/, which resolves to the non-existent src/components/assets/images/. The actual SVGs are at src/assets/images/.

Update both files to use ../../../assets/images/:

  • Component: lines 6-7
  • Test: lines 41 and 45
🤖 Prompt for AI Agents
In src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusButton.test.tsx
around lines 41 to 47 and in
src/components/EIP7702UpgradeModal/EIP7702UpgradeStatusButton.tsx around lines 6
to 7, the SVG import paths point to ../../assets/images/ which resolves
incorrectly; update both import/mock paths to ../../../assets/images/ so they
reference src/assets/images/ (change the two mock paths in the test at lines 41
and 45 and the two SVG imports in the component at lines 6-7).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed

Copy link
Contributor

Choose a reason for hiding this comment

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

@RanaBug Thank you for fixing the SVG asset mock paths! 🎉


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@github-actions github-actions bot requested a deployment to Preview (feat/PRO-3797/7702-onboarding) November 2, 2025 22:56 Abandoned
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9864eb2 and 77f1413.

📒 Files selected for processing (1)
  • src/services/walletConnect.ts (9 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/services/walletConnect.ts (1)
src/utils/walletConnect.ts (4)
  • PERSONAL_SIGN (4-4)
  • ETH_SIGN_TYPED_DATA (8-8)
  • ETH_SIGN_TYPED_DATA_V4 (9-9)
  • ETH_SEND_TX (6-6)
⏰ 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: lint
  • GitHub Check: unit-tests

@github-actions github-actions bot requested a deployment to Preview (feat/PRO-3797/7702-onboarding) November 3, 2025 14:59 Abandoned
@github-actions github-actions bot requested a deployment to Preview (feat/PRO-3797/7702-onboarding) November 3, 2025 15:03 Abandoned
@github-actions github-actions bot requested a deployment to Preview (feat/PRO-3797/7702-onboarding) November 3, 2025 15:23 Abandoned
@github-actions github-actions bot temporarily deployed to Preview (feat/PRO-3797/7702-onboarding) November 3, 2025 15:30 Inactive
Copy link
Collaborator

@IAmKio IAmKio left a comment

Choose a reason for hiding this comment

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

Just two small changes and a few non-blocking questions but other than that - looking good!

@github-actions github-actions bot temporarily deployed to Preview (feat/PRO-3797/7702-onboarding) November 4, 2025 15:55 Inactive
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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx (1)

1383-1399: Restore the chainId fallback for payload transactions.
Line [1388] now fails when payloadTx.chainId is missing, but that field is optional in SendModalData. WalletConnect payloads routinely omit it, so instead of falling back to etherspotDefaultChainId we now abort the flow.

-        const chainIdToUse = payloadTx?.chainId;
+        const chainIdToUse =
+          payloadTx?.chainId ?? etherspotDefaultChainId;
♻️ Duplicate comments (3)
src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusIcon.test.tsx (1)

138-151: Memoization test doesn't verify actual memoization behavior.

This test checks that the element remains in the document after rerender but doesn't prove React.memo prevents re-renders. The test would pass even without memoization. Consider renaming to "renders consistently with identical props" or adding a comment noting the limitation.

src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusButton.test.tsx (2)

168-195: Button styling tests only verify existence, not correctness.

The styling tests use container.querySelector('[class*="bg-"]') which only confirms some element has a background class, not that the button itself has the correct status-specific classes. Consider asserting specific classes on the button element.


198-211: Memoization test doesn't verify actual memoization.

This test rerenders with identical props and checks the element is still present, but doesn't prove memoization prevents re-renders. Consider renaming to accurately reflect what's tested or add a comment noting the limitation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96301d8 and c2811d5.

⛔ Files ignored due to path filters (5)
  • package-lock.json is excluded by !**/package-lock.json
  • src/apps/pillarx-app/components/TokenMarketDataRow/tests/__snapshots__/LeftColumnTokenMarketDataRow.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/TokensWithMarketDataTile/test/__snapshots__/TokensWithMarketDataTile.test.tsx.snap is excluded by !**/*.snap
  • src/components/EIP7702UpgradeModal/tests/__snapshots__/EIP7702UpgradeAction.test.tsx.snap is excluded by !**/*.snap
  • src/components/EIP7702UpgradeModal/tests/__snapshots__/EIP7702UpgradeStatusIcon.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (16)
  • __mocks__/useTransactionKit.ts (1 hunks)
  • src/apps/pillarx-app/components/PortfolioOverview/PortfolioOverview.tsx (2 hunks)
  • src/apps/pillarx-app/components/WalletPortfolioButtons/WalletPortfolioButtons.tsx (4 hunks)
  • src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx (15 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeAction.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeDetails.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeStatus.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeAction.test.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeDetails.test.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusButton.test.tsx (1 hunks)
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusIcon.test.tsx (1 hunks)
  • src/hooks/useEIP7702Upgrade.tsx (1 hunks)
  • src/hooks/useWalletModeVerification.tsx (1 hunks)
  • src/services/walletConnect.ts (9 hunks)
  • src/utils/eip7702Authorization.ts (1 hunks)
  • src/utils/upgrade.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeDetails.tsx
  • src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeAction.test.tsx
  • src/components/EIP7702UpgradeModal/EIP7702UpgradeAction.tsx
  • src/apps/pillarx-app/components/WalletPortfolioButtons/WalletPortfolioButtons.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-04T14:34:00.341Z
Learnt from: RanaBug
Repo: pillarwallet/x PR: 445
File: src/containers/Authorized.tsx:63-77
Timestamp: 2025-11-04T14:34:00.341Z
Learning: In src/containers/Authorized.tsx, the tempKit useEffect intentionally excludes chainId from its dependency array because the kit is used by useWalletModeVerification to check wallet mode across all supported chains, regardless of the currently selected chainId. The chainId parameter is only used for initial kit configuration and does not affect the multi-chain verification results.

Applied to files:

  • src/apps/pillarx-app/components/PortfolioOverview/PortfolioOverview.tsx
  • src/services/walletConnect.ts
  • src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx
  • src/hooks/useWalletModeVerification.tsx
  • src/hooks/useEIP7702Upgrade.tsx
  • src/utils/eip7702Authorization.ts
📚 Learning: 2025-08-20T09:14:16.888Z
Learnt from: RanaBug
Repo: pillarwallet/x PR: 374
File: src/apps/pillarx-app/index.tsx:12-12
Timestamp: 2025-08-20T09:14:16.888Z
Learning: In this codebase, Transaction Kit providers are set up at the container level (src/containers/Authorized.tsx), not at individual app component levels. App components like src/apps/pillarx-app/index.tsx are children that consume the context through the provider tree.

Applied to files:

  • src/apps/pillarx-app/components/PortfolioOverview/PortfolioOverview.tsx
📚 Learning: 2025-05-28T14:30:02.702Z
Learnt from: RanaBug
Repo: pillarwallet/x PR: 320
File: src/components/BottomMenuModal/HistoryModal/TransactionInfo.tsx:177-182
Timestamp: 2025-05-28T14:30:02.702Z
Learning: In the transaction history tracking feature, chain ID validation is performed earlier in the flow before the values reach the TransactionInfo component, so additional validation at the display level is not needed.

Applied to files:

  • src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx
  • src/hooks/useEIP7702Upgrade.tsx
🧬 Code graph analysis (6)
src/utils/upgrade.tsx (2)
src/apps/pulse/types/types.ts (1)
  • ButtonConfig (61-66)
src/components/EIP7702UpgradeModal/types.ts (1)
  • UpgradeStatus (1-6)
src/services/walletConnect.ts (2)
src/utils/walletConnect.ts (4)
  • PERSONAL_SIGN (4-4)
  • ETH_SIGN_TYPED_DATA (8-8)
  • ETH_SIGN_TYPED_DATA_V4 (9-9)
  • ETH_SEND_TX (6-6)
src/apps/deposit/utils/blockchain.tsx (1)
  • getNetworkViem (71-94)
src/components/BottomMenuModal/SendModal/SendModalTokensTabView.tsx (2)
src/utils/blockchain.ts (1)
  • supportedChains (157-159)
src/utils/eip7702Authorization.ts (1)
  • getEIP7702AuthorizationIfNeeded (16-95)
src/components/EIP7702UpgradeModal/EIP7702UpgradeStatus.tsx (2)
src/components/EIP7702UpgradeModal/types.ts (1)
  • UpgradeStatus (1-6)
src/utils/upgrade.tsx (1)
  • getStatusConfig (101-103)
src/hooks/useWalletModeVerification.tsx (3)
src/utils/blockchain.ts (1)
  • visibleChains (161-163)
src/utils/eip7702Authorization.ts (1)
  • OUR_EIP7702_IMPLEMENTATION_ADDRESS (5-6)
src/utils/common.ts (1)
  • sanitizeError (83-110)
src/hooks/useEIP7702Upgrade.tsx (4)
src/hooks/useTransactionDebugLogger.tsx (1)
  • useTransactionDebugLogger (1-15)
src/hooks/useEIP7702Info.tsx (1)
  • useEIP7702Info (6-12)
src/apps/pillarx-app/reducer/WalletPortfolioSlice.ts (2)
  • setIsEIP7702Eligible (140-142)
  • setIsUpgradeWalletModalOpen (137-139)
src/apps/deposit/utils/blockchain.tsx (1)
  • getNetworkViem (71-94)
⏰ 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). (3)
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: build
🔇 Additional comments (12)
src/services/walletConnect.ts (4)

1178-1205: LGTM! Consistent wallet mode handling for typed data signing.

The branching logic for delegatedEoa vs modular mode is clean and consistent with the PERSONAL_SIGN flow. Account validation is properly in place.


1208-1250: LGTM! Transaction handling preserves existing flow.

The ETH_SEND_TX handling maintains the established pattern for both approval and regular transactions. Approval detection via function selector 0x095ea7b3 is standard.


1261-1271: Good defensive error handling.

The nested try-catch ensures cleanup happens even when the error response itself fails, preventing cascading relay failures from leaving the app in an inconsistent state.


1333-1339: LGTM! Graceful handling of relayer errors.

The new handleUnknownEvent handler appropriately logs relayer errors without disrupting the session lifecycle. These are typically benign events from expired sessions or incompatible dApps.

Also applies to: 1350-1353, 1368-1373

__mocks__/useTransactionKit.ts (1)

15-15: LGTM! Mock correctly extends provider API.

The getWalletMode mock returning 'modular' properly supports the new wallet mode detection used throughout the EIP-7702 flows.

src/apps/pillarx-app/components/PortfolioOverview/PortfolioOverview.tsx (1)

36-54: LGTM! Correct wallet mode check for dropdown visibility.

The logic properly hides the WalletConnect dropdown in delegatedEoa mode, aligning with the two-mode architecture. The explanatory comment is helpful.

src/components/EIP7702UpgradeModal/EIP7702UpgradeStatus.tsx (1)

1-35: LGTM! Clean composition pattern.

The component cleanly composes the icon, label, and button elements using the status config. The structure is straightforward and maintainable.

src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusIcon.test.tsx (1)

1-167: Comprehensive test coverage for icon component.

The test suite thoroughly covers rendering across all statuses, icon selection, and prop changes. The mocks are properly configured and tests are well-structured.

src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeStatusButton.test.tsx (1)

1-227: Thorough test coverage for button component.

The test suite comprehensively covers rendering, icon states, and user interactions across all statuses. The mocks properly simulate dependencies.

src/utils/upgrade.tsx (2)

20-96: LGTM! Well-structured config mapping.

The STATUS_CONFIG and BUTTON_CONFIG provide clean, centralized configuration for all upgrade statuses. The color scheme is consistent and the Tailwind classes are properly formatted.


98-110: LGTM! Simple and effective getter functions.

The getter functions provide type-safe access to the configuration mappings.

src/components/EIP7702UpgradeModal/tests/EIP7702UpgradeDetails.test.tsx (1)

1-258: Excellent comprehensive test coverage.

This test suite thoroughly covers:

  • All status states and their visual representation
  • Step status propagation logic
  • Timestamp display behavior
  • User interaction flows (onClose vs onCloseModal)
  • Edge cases with missing data

The mock structure enables deterministic testing of complex status flows.

Copy link
Collaborator

@IAmKio IAmKio left a comment

Choose a reason for hiding this comment

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

LGTM!

@github-actions github-actions bot temporarily deployed to Preview (feat/PRO-3797/7702-onboarding) November 4, 2025 16:53 Inactive
@RanaBug RanaBug merged commit 1b463ca into staging Nov 4, 2025
5 of 6 checks passed
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/hooks/useEIP7702Upgrade.tsx (2)

98-98: Consider dynamic gas estimation for better accuracy.

The hardcoded estimate of 50,000 gas units may not reflect actual transaction costs. For production use, consider estimating gas dynamically using the actual transaction data (e.g., via publicClient.estimateGas with the EIP-7702 authorization transaction parameters) to provide users with more accurate cost information.


149-149: Optional: Add defensive error handling for localStorage.

While localStorage access is generally reliable, wrapping it in a try/catch block would make the code more defensive against edge cases (e.g., storage quotas, browser restrictions).

Example:

let wasDismissed = false;
try {
  wasDismissed = localStorage.getItem('eip7702_upgrade_dismissed') === 'true';
} catch (error) {
  // Silently handle localStorage errors
  transactionDebugLog('Failed to check localStorage:', error);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2811d5 and 3f8aa18.

📒 Files selected for processing (1)
  • src/hooks/useEIP7702Upgrade.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-05-28T14:30:02.702Z
Learnt from: RanaBug
Repo: pillarwallet/x PR: 320
File: src/components/BottomMenuModal/HistoryModal/TransactionInfo.tsx:177-182
Timestamp: 2025-05-28T14:30:02.702Z
Learning: In the transaction history tracking feature, chain ID validation is performed earlier in the flow before the values reach the TransactionInfo component, so additional validation at the display level is not needed.

Applied to files:

  • src/hooks/useEIP7702Upgrade.tsx
📚 Learning: 2025-11-04T14:34:00.341Z
Learnt from: RanaBug
Repo: pillarwallet/x PR: 445
File: src/containers/Authorized.tsx:63-77
Timestamp: 2025-11-04T14:34:00.341Z
Learning: In src/containers/Authorized.tsx, the tempKit useEffect intentionally excludes chainId from its dependency array because the kit is used by useWalletModeVerification to check wallet mode across all supported chains, regardless of the currently selected chainId. The chainId parameter is only used for initial kit configuration and does not affect the multi-chain verification results.

Applied to files:

  • src/hooks/useEIP7702Upgrade.tsx
🧬 Code graph analysis (1)
src/hooks/useEIP7702Upgrade.tsx (4)
src/hooks/useTransactionDebugLogger.tsx (1)
  • useTransactionDebugLogger (1-15)
src/hooks/useEIP7702Info.tsx (1)
  • useEIP7702Info (6-12)
src/apps/pillarx-app/reducer/WalletPortfolioSlice.ts (2)
  • setIsEIP7702Eligible (140-142)
  • setIsUpgradeWalletModalOpen (137-139)
src/apps/deposit/utils/blockchain.tsx (1)
  • getNetworkViem (71-94)
⏰ 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). (3)
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: build
🔇 Additional comments (1)
src/hooks/useEIP7702Upgrade.tsx (1)

170-187: LGTM!

The wrapper functions and return statement are well-structured. The public API provides clear separation between manual upgrade actions (handleUpgradeClick) and auto-check flows (checkOnLogin), and exposes all necessary state and functions for consumers.

Comment on lines +53 to +73
const checkEligibility = useCallback(() => {
// If user has already completed the upgrade, do not allow upgrading again
if (hasCompletedUpgrade) {
dispatch(setIsEIP7702Eligible(false));
return false;
}

const selectedChainEIP7702Info = eip7702Info[chainId]; // Default mainnet chainId is 1
const hasSelectedChainEIP7702 =
selectedChainEIP7702Info?.hasImplementation || false;

const eligible =
!hasSelectedChainEIP7702 &&
Object.keys(eip7702Info).length > 0 &&
!!walletAddress;

dispatch(setIsEIP7702Eligible(eligible));

return eligible;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [eip7702Info, walletAddress, isEligible, hasCompletedUpgrade, chainId]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove unused dependency from checkEligibility.

The dependency array includes isEligible (Line 73), but this value is never referenced inside the callback. The function only writes to isEligible via dispatch but never reads it. Including unused dependencies causes unnecessary re-computation and can lead to subtle bugs.

Apply this diff to remove the unused dependency:

     return eligible;
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [eip7702Info, walletAddress, isEligible, hasCompletedUpgrade, chainId]);
+  }, [eip7702Info, walletAddress, hasCompletedUpgrade, chainId]);
🤖 Prompt for AI Agents
In src/hooks/useEIP7702Upgrade.tsx around lines 53 to 73, the checkEligibility
callback includes an unused dependency isEligible in its dependency array;
remove isEligible from the array so the callback depends only on eip7702Info,
walletAddress, hasCompletedUpgrade, and chainId (update the dependency list
accordingly) to prevent unnecessary re-renders and false positives from ESLint.

@coderabbitai coderabbitai bot mentioned this pull request Nov 7, 2025
3 tasks
aldin4u added a commit that referenced this pull request Nov 22, 2025
- Fixed 3 no-lonely-if errors by converting else-if pattern
- Fixed 2 no-continue errors by refactoring to use nested conditionals
- All changes in parseSearchData.ts
- Tests still passing: Search (19/20, 1 skipped), AppWrapper (10/10)
- Left Prettier formatting errors to avoid Tailwind corruption risk

Following PR #445 methodology: manual fixes, verified after each change
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants