Skip to content

Conversation

@NeOMakinG
Copy link
Collaborator

@NeOMakinG NeOMakinG commented Jan 22, 2026

Description

Attempt at fixing the wallet import when quitting by closing the drawer instead of going to the wallet view

Issue (if applicable)

closes #11142

Risk

Low

High Risk PRs Require 2 approvals

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

Testing

  • Using the mobile app, create a new wallet, instead of clicking "View wallet" dismiss the modal, notice the new wallet is in the wallet list
  • Same thing but with import wallet ("View wallet" action can be slow to use, but there is a loader showing the user something is happening)

Engineering

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

Screenshots (if applicable)

https://jam.dev/c/b0810ba5-348a-42a6-a3a7-f539f41e2d6b

Summary by CodeRabbit

  • Refactor
    • Improved wallet creation and import flows with enhanced loading indicators during operations
    • Strengthened wallet connection reliability with safeguards against repeated attempts and better error messaging

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

Minimoi and others added 4 commits January 21, 2026 17:05
…en attempted

Add saveAttemptedRef to prevent duplicate wallet saves when both handleViewWallet
and handleClose could trigger saveAndSelectWallet. The ref is checked at the
start of saveAndSelectWallet and set to true before proceeding with the save.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…) on mount

This ensures the wallet is saved immediately when the CreateSuccess screen
renders, rather than only when the user clicks the "View wallet" button.
The existing saveAttemptedRef prevents duplicate save attempts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ady been

Add hasConnectedRef to prevent duplicate wallet connection attempts in
ImportSuccess component. This follows the same pattern used in ManualBackup.tsx.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ction()

Adds a useEffect hook that calls handleWalletConnection() on component mount.
This ensures the wallet is connected immediately when ImportSuccess mounts,
rather than only when the user clicks the close/view wallet button.

Duplicate calls are prevented by the existing hasConnectedRef guard in
handleWalletConnection().

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

Warning

Rate limit exceeded

@NeOMakinG has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 32 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Refactored mobile wallet creation and import flows to automatically persist wallets without requiring explicit user interaction. Introduced React hooks for managing async save/connect operations with ref-based guards against duplicate executions. Migrated wallet list fetching in MobileConnect to React Query for improved state management and caching.

Changes

Cohort / File(s) Summary
Mobile Wallet Dialog Success Flows
src/components/MobileWalletDialog/routes/CreateWallet/CreateSuccess.tsx, src/components/MobileWalletDialog/routes/ImportWallet/ImportSuccess.tsx
Added useEffect-driven auto-save logic on component mount using refs (saveAttemptedRef, connectionAttemptedRef) to prevent duplicate operations. Introduced isConnecting state for button loading UI. Separated save and connection workflows; wallets now persist automatically before user interacts with the dialog.
Mobile Connect Page
src/pages/ConnectWallet/MobileConnect.tsx
Replaced local state-based wallet fetching with useQuery (React Query). Removed manual async fetch effect and integrated queryError handling. Updated conditional rendering to depend on query-derived wallets and isLoading state.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Dialog as CreateSuccess/<br/>ImportSuccess Component
    participant Storage as Vault/Storage
    participant Query as React Query
    participant Adapter as Mobile Wallet<br/>Adapter
    participant State as Global Wallet<br/>State

    Note over Dialog: Component mounts
    Dialog->>Dialog: Check saveAttemptedRef
    
    alt Save not attempted
        Dialog->>Storage: saveWallet(vault label, mnemonic)
        Storage-->>Dialog: Success
        Dialog->>Query: Invalidate listWallets cache
        Dialog->>Dialog: Set saveAttemptedRef = true
    end

    Note over Dialog: Initiate connection flow
    Dialog->>Dialog: Check connectionAttemptedRef
    
    alt Connect not attempted
        Dialog->>Adapter: Connect via Mobile adapter
        Adapter-->>State: Update wallet state
        Dialog->>State: Mark wallet as connected
        Dialog->>Dialog: Set connectionAttemptedRef = true
        Dialog->>Dialog: Set isConnecting = false
    end

    Dialog->>Dialog: Close dialog
    User-->>Dialog: (or close dialog manually)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

high risk

Suggested reviewers

  • premiumjibles
  • 0xApotheosis

Poem

🐰 Wallets now persist with pride,
No need to click "View" as guide,
Refs guard against double-do,
Save and connect, see it through!
React Query caches the way,
Your wallet's safe—hip hip hooray! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary change: fixing wallet import on mobile by ensuring wallets persist when users dismiss the final screen instead of clicking "View wallet".
Linked Issues check ✅ Passed The PR implements all code-level requirements from #11142: auto-saving wallets on mount in CreateSuccess, auto-connecting wallets on mount in ImportSuccess, preventing duplicate operations via refs, adding loading state management, and integrating React Query for wallet state management.
Out of Scope Changes check ✅ Passed All code changes directly address the issue: adding saveAttemptedRef/connectionAttemptedRef guards, useEffect hooks for auto-save/connect, loading state UI, React Query integration, and modal dismiss behavior—all focused on solving the wallet persistence problem.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch auto-claude/010-clicking-off-of-view-wallet-in-create-wallet-flow-

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.

@NeOMakinG NeOMakinG changed the title Fix Mobile Wallet Persistence on View Wallet Screen Dismissal fix: attempt at fixing wallet import on mobile Jan 22, 2026
@NeOMakinG NeOMakinG force-pushed the auto-claude/010-clicking-off-of-view-wallet-in-create-wallet-flow- branch from 91abb9b to 46b43d9 Compare January 27, 2026 00:07
NeOMakinG and others added 2 commits January 27, 2026 01:08
Removes autoclaude configuration files that shouldn't be tracked in git:
- .auto-claude-security.json
- .auto-claude-status
- .claude_settings.json

Reverts .gitignore to remove autoclaude directory entry.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@NeOMakinG NeOMakinG marked this pull request as ready for review January 27, 2026 00:09
@NeOMakinG NeOMakinG requested a review from a team as a code owner January 27, 2026 00:09
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: 3

Caution

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

⚠️ Outside diff range comments (1)
src/components/MobileWalletDialog/routes/ImportWallet/ImportSuccess.tsx (1)

52-103: Allow retry and only close on successful connect.

connectionAttemptedRef is set before any async work and never reset. Since handleWalletConnection swallows errors, handleViewWallet will still close on failure and subsequent taps become no-ops, leaving the wallet unconnected with no retry path.

✅ Suggested fix
-  const handleWalletConnection = useCallback(async () => {
-    if (connectionAttemptedRef.current) return
-    if (!location.state?.vault) return
-    connectionAttemptedRef.current = true
-    const adapter = await getAdapter(KeyManager.Mobile)
-    if (!adapter) throw new Error('Native adapter not found')
-    try {
+  const handleWalletConnection = useCallback(async () => {
+    if (connectionAttemptedRef.current) return false
+    if (!location.state?.vault) return false
+    connectionAttemptedRef.current = true
+    try {
+      const adapter = await getAdapter(KeyManager.Mobile)
+      if (!adapter) throw new Error('Native adapter not found')
       const deviceId = location.state.vault.id ?? ''
       const wallet = (await adapter.pairDevice(deviceId)) as NativeHDWallet
       const mnemonic = location.state.vault.mnemonic
@@
-        appDispatch(setWelcomeModal({ show: true }))
+        appDispatch(setWelcomeModal({ show: true }))
+        return true
       }
     } catch (e) {
       console.log(e)
+      connectionAttemptedRef.current = false
+      return false
     }
   }, [getAdapter, location.state?.vault, dispatch, localWallet, appDispatch, setWelcomeModal])

   const handleViewWallet = useCallback(async () => {
     setIsConnecting(true)
     try {
-      await handleWalletConnection()
-      onClose()
-      setTimeout(() => location.state?.vault?.revoke(), 500)
+      const didConnect = await handleWalletConnection()
+      if (!didConnect) return
+      onClose()
+      setTimeout(() => location.state?.vault?.revoke(), 500)
     } finally {
       setIsConnecting(false)
     }
   }, [onClose, handleWalletConnection, location.state?.vault])
🤖 Fix all issues with AI agents
In `@src/components/MobileWalletDialog/routes/CreateWallet/CreateSuccess.tsx`:
- Around line 40-55: Wrap the save logic in saveWallet in a try-catch: try the
existing checks and calls to addWallet and queryClient.invalidateQueries, and in
catch handle errors by resetting saveAttemptedRef.current (so a retry is
possible), log the error (or surface it via the app's notification/toast/error
state) and ensure any created wallet is revoked if partially created; keep the
existing success flow (invalidateQueries and wallet.revoke()) inside the try
block. Use the existing symbols saveWallet, addWallet,
queryClient.invalidateQueries, saveAttemptedRef, and location.state?.vault to
locate where to add the try-catch and error handling.
- Around line 40-55: saveWallet currently calls addWallet without error handling
and handleWalletConnection calls addWallet again, risking duplicates; change
saveWallet to wrap the addWallet call in try/catch, log or show an error toast
on failure, and store the resulting wallet reference in component state (e.g.,
useState walletRef) instead of only using saveAttemptedRef; update
handleWalletConnection to reuse the stored walletRef (and only call addWallet if
walletRef is null) and remove the duplicated addWallet invocation; ensure you
still call queryClient.invalidateQueries(['listWallets']) and wallet.revoke()
when appropriate, and replace the console.log(e) in handleWalletConnection with
structured logging or a user-facing error toast.

In `@src/pages/ConnectWallet/MobileConnect.tsx`:
- Around line 91-101: The current useMemo for error (involving queryError,
wallets.length, isLoading) sometimes returns queryError.message (a raw string)
which is passed into <Text translation={error} />; change the logic in the
useMemo so it always returns a translation key (e.g.
'walletProvider.shapeShift.load.error.fetchingWallets' or existing noWallet key)
rather than raw Error.message, and if you still want the raw error for
debugging, log queryError (when instanceof Error) via console.error or process
logger inside the same branch; update references to useMemo, queryError, wallets
and isLoading accordingly so <Text translation={error} /> always receives a
translation key.
🧹 Nitpick comments (2)
src/pages/ConnectWallet/MobileConnect.tsx (1)

78-89: Consider implications of gcTime: 0 on user experience.

Setting gcTime: 0 means the query cache is garbage collected immediately when the component unmounts. Combined with staleTime: 0, this effectively disables React Query's caching benefits entirely. If a user navigates away briefly and returns, they'll see a full loading state again instead of instant data with a background refetch.

If the intent is to ensure fresh data on every mount (which makes sense for a wallet list), consider keeping staleTime: 0 but using a small gcTime (e.g., gcTime: 5000) to avoid unnecessary loading flickers during quick navigation transitions.

💡 Optional: Allow brief cache retention for smoother UX
   const {
     isLoading,
     data: wallets = [],
     error: queryError,
   } = useReactQuery({
     queryKey: ['listWallets'],
     staleTime: 0,
-    gcTime: 0,
+    gcTime: 5000, // Keep cache briefly to avoid loading flicker on quick re-mounts
     retry: false,
     refetchOnMount: true,
     queryFn: listWallets,
   })
src/components/MobileWalletDialog/routes/CreateWallet/CreateSuccess.tsx (1)

101-103: Use structured logging instead of console.log.

Per coding guidelines, errors should use structured logging with relevant context. Consider using console.error with meaningful context or the project's logger utility.

♻️ Suggested improvement
-        } catch (e) {
-          console.log(e)
-        }
+        } catch (e) {
+          console.error('[CreateSuccess] Failed to connect wallet:', e)
+        }

Copy link
Member

@0xApotheosis 0xApotheosis left a comment

Choose a reason for hiding this comment

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

I think CodeRabbit is onto something with the comment below.

✅ Tapping outside the final modal correctly saves the wallet
✅ Tapping the X on the final modal correctly saves the wallet
❌ Clicking "View Wallet" creates two wallets
❌ One time I clicked "View Wallet" and it crashed the dev server

ScreenRecording_01-27-2026.14-45-40_1.MP4
Image

@NeOMakinG
Copy link
Collaborator Author

I think CodeRabbit is onto something with the comment below.

✅ Tapping outside the final modal correctly saves the wallet ✅ Tapping the X on the final modal correctly saves the wallet ❌ Clicking "View Wallet" creates two wallets ❌ One time I clicked "View Wallet" and it crashed the dev server

ScreenRecording_01-27-2026.14-45-40_1.MP4
Image

I probably broke it after testing by cleaning up (I can be stupid)

It should be better now! Also took care of safely revoking either ways!

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.

Clicking off of view wallet in create wallet flow should still allow users newly created/improted wallet to exist.

3 participants