--- title: "MetaMask Wallet Login Does Not Surface Address — Debug Report" type: debug date: 2026-06-02 severity: high status: root-caused --- # MetaMask Wallet Login Does Not Surface Address — Debug Report ## Summary MetaMask QR login and mobile deeplink login can be approved in MetaMask, but the ARK frontend does not write the approved wallet address into the local wallet session; the mobile QR waiting text is also incorrectly TokenPocket-specific for all wallets. ## Expected Behavior - Selecting MetaMask and approving the connection should result in the page showing the connected wallet address. - Mobile MetaMask deeplink login should return/reconnect to the page and complete local no-signature login with `local-wallet:
`. - QR login copy should be generic or absent; it should not say “waiting in TokenPocket” when the selected wallet is MetaMask or imToken. ## Actual Behavior - Terry can approve MetaMask QR/deeplink login, but the web page does not show the authorized address. - The QR panel uses TokenPocket-specific copy for any wallet on mobile, e.g. imToken QR login still shows a TokenPocket waiting message. ## Reproduction Steps 1. Open the public frontend and open the wallet login modal. 2. Select MetaMask. 3. Use either: - QR login: scan the QR using MetaMask and approve, or - Mobile app login: tap “Open wallet app”, approve in MetaMask, then return to the web page. 4. Observe that the page does not show the wallet address. 5. Select imToken QR login on mobile and observe that the QR panel displays TokenPocket-specific waiting text. ## Environment - Project: Arkie Library Frontend (`ark-database-web`) - Branch context: `terry-wallet-login` - Stack: React 18, Vite, TypeScript, RainbowKit, Wagmi, WalletConnect/Reown - Wallets involved: MetaMask Mobile, TokenPocket, imToken - Backend auth endpoints intentionally not required for this flow; login is local no-signature wallet session. ## Root Cause Analysis ### Failure Chain 1. `WalletLoginModal` calls `wc.start(kind, mode)` for all wallet app/QR flows. 2. `useWalletConnectLogin.start()` currently chooses the first generic WalletConnect connector for non-injected flows: - `connectors.find((item) => item.type === "walletConnect") ?? connectors.find((item) => item.id === "walletConnect")` 3. On MetaMask mobile, RainbowKit’s own MetaMask wallet definition intentionally uses Wagmi’s `metaMask()` / MetaMask SDK connector, not the generic WalletConnect connector. 4. The custom hook bypasses that MetaMask-specific connector on mobile, so MetaMask SDK deeplink/reconnect handling is not used. 5. The hook only calls `completeLogin(localWalletToken(address), address)` inside the awaited `connectAsync(...)` result path. 6. If MetaMask approval completes while the browser is backgrounded, after a page reload, or through a restored Wagmi connection, there is no `useAccount`/reconnect bridge that converts the Wagmi connected address into the app’s local wallet session. 7. `RainbowWalletProvider` calls `useReconnect()`, but this only restores Wagmi connection state; it does not update `WalletProvider` unless `useWalletConnectLogin` observes the restored account and calls `completeLogin`. 8. Therefore MetaMask may be approved/connected at the wallet/Wagmi layer but the ARK UI still has no `local-wallet:` token and shows logged-out/no address. ### Root Cause The MetaMask flow is treated as a generic WalletConnect flow, but RainbowKit/Wagmi have MetaMask-specific mobile behavior. Additionally, local ARK wallet login is tied only to the synchronous `connectAsync` return path instead of being derived from Wagmi account state/reconnect events. This misses MetaMask connections that resolve via mobile app backgrounding, deep link return, QR approval, or page reload. ### Evidence - File: `src/wallet/useWalletConnectLogin.ts` — connector selection prefers `item.type === "walletConnect"` for all wallets, so mobile MetaMask does not use the RainbowKit/Wagmi MetaMask connector. - File: `src/wallet/useWalletConnectLogin.ts` — `completeLogin(localWalletToken(...), ...)` only runs after `await connectAsync(...)`; there is no `useAccount` effect to complete local login when Wagmi is already/reconnected. - File: `src/wallet/RainbowWalletProvider.tsx` — `WalletReconnectOnMount` calls `useReconnect()`, but no downstream code maps the restored Wagmi account into `WalletProvider`. - File: `node_modules/@rainbow-me/rainbowkit/dist/wallets/walletConnectors/chunk-BQHQU37S.js` — RainbowKit MetaMask wallet uses `metaMask()` connector on mobile and comments that “MetaMask mobile deep linking [is] handled by wagmi”. The custom hook bypasses this by selecting a generic WalletConnect connector. - File: `src/wallet/WalletLoginModal.tsx` — QR text uses `mobileDevice ? t("walletTpWaiting") : t("walletQrUseAnotherDevice")` for every selected wallet, causing TokenPocket-specific copy for MetaMask/imToken. - File: `src/locales/en.ts` and `src/locales/zh-CN.ts` — `walletQrUseAnotherDevice` also explicitly mentions TokenPocket, so even desktop/generic QR copy is wallet-specific. ## Affected Files - `src/wallet/useWalletConnectLogin.ts` — connector choice, deeplink generation, QR URI generation, local-login completion. - `src/wallet/WalletLoginModal.tsx` — misleading QR panel copy. - `src/wallet/RainbowWalletProvider.tsx` — currently reconnects Wagmi but does not by itself complete local login. - `src/locales/*.ts` — QR copy currently contains TokenPocket-specific text. ## Suggested Fix Use the wallet-specific connector when a wallet is selected, especially MetaMask, and add a Wagmi account/reconnect bridge that completes the local wallet session whenever Wagmi has an address. Remove or generalize TokenPocket-specific QR waiting copy. ### Fix Strategy 1. In `useWalletConnectLogin.ts`, prefer a connector matching `preferredWallet` before falling back to generic WalletConnect: - MetaMask: `id === "metaMask"` or `type === "metaMask"` - imToken/TokenPocket: matching wallet id when present, otherwise generic WalletConnect 2. Add `useAccount()` inside `useWalletConnectLogin` and a `useEffect` that calls `completeLogin(localWalletToken(address), address)` when Wagmi reports `isConnected && address`. 3. For MetaMask QR, transform the displayed QR value with the same wallet-specific URI RainbowKit uses: `https://metamask.app.link/wc?uri=