---
title: "imToken opens in-app browser but cannot get wallet address — Debug Report"
type: debug
date: 2026-06-04
severity: high
status: needs-investigation
---

# imToken opens in-app browser but cannot get wallet address — Debug Report

## Summary

imToken can open the site in its in-app browser, but the frontend does not obtain a wallet address and the login flow stays at `connected: no`.

## Expected Behavior

1. User taps imToken from Chrome or from imToken's in-app browser.
2. The site detects the imToken injected wallet provider.
3. The frontend requests accounts via the injected provider.
4. The frontend receives a wallet address and completes login.

## Actual Behavior

The page opens inside imToken, but the wallet modal remains stuck with:

- `state: connecting`
- `connected: no`
- `address: -`
- `qr: -`

The supplied screenshot shows the page loaded at `192.168.1.187` and the imToken card selected.

## Reproduction Steps

1. Open the site in Chrome on mobile.
2. Tap wallet login.
3. Select imToken.
4. The app opens imToken's in-app browser.
5. Login does not complete and no wallet address appears.
6. Open the same page inside imToken's in-app browser and tap login again.
7. The wallet debug panel still shows `connected: no` and `address: -`.

## Environment

- Branch: `terry-wallet-login`
- Frontend URL shown in screenshot: `192.168.1.187`
- Wallet: imToken mobile in-app browser
- Network path: local LAN IP, likely non-HTTPS

## Root Cause Analysis

### Failure Chain

1. `WalletLoginModal` selects imToken and exposes the mobile actions.
2. `openWalletAppDirect(kind)` first checks `getInjectedWallet(kind)`.
3. If no injected provider is detected, the flow deep-links to imToken or falls through to `useWalletConnectLogin.start()` depending on which action is tapped.
4. `useWalletConnectLogin.start()` sets `state` to `connecting` before trying direct injected login.
5. The direct injected branch only runs when `getInjectedWallet(preferredWallet)` returns a provider.
6. The screenshot shows `state: connecting`, `connected: no`, `address: -`, and `qr: -`, which means no address was completed through either direct injected login or WalletConnect.
7. `AutoInjectedLogin` can auto-start imToken login without `?autoLogin=imToken` only if `isImTokenBrowser()` detects the imToken user agent; it still depends on `waitForInjected("imToken")`, which depends on `getInjectedWallet("imToken")`.
8. Therefore the app is not obtaining a usable imToken injected provider, or the provider is present but `eth_accounts` / `eth_requestAccounts` returns no valid address.

### Root Cause

The immediate root cause is failure to obtain a usable injected imToken provider/account. The most likely reason from the screenshot is that the page is running on raw LAN IP `192.168.1.187`, likely over HTTP. imToken may not inject its EIP-1193 provider into non-HTTPS/raw-IP pages, or its iOS in-app browser may not expose a user agent/provider shape that matches the current checks.

The code currently assumes at least one of these is true:

- URL contains `?autoLogin=imToken`, or
- `navigator.userAgent` matches `/imtoken/i`, and
- `window.ethereum` is present and accepted by `getInjectedWallet("imToken")`, and
- `eth_accounts` or `eth_requestAccounts` returns a valid `0x...` address.

The observed behavior shows that this assumption chain is breaking before a valid address is produced.

### Evidence

- File: `src/wallet/WalletLoginModal.tsx` — `openWalletAppDirect()` uses `getInjectedWallet(kind)` as the gate for direct injected login; if it is false, the flow navigates/deep-links instead of reading an address.
- File: `src/wallet/useWalletConnectLogin.ts` — `start()` sets `state` to `connecting`; the imToken direct local-session path only executes inside `if (mode === "deeplink" && preferredWallet && getInjectedWallet(preferredWallet))`.
- File: `src/wallet/AutoInjectedLogin.tsx` — auto-login picks imToken from the query parameter or `isImTokenBrowser()`, then waits for `getInjectedWallet("imToken")` before calling `connectInjectedWallet("imToken")`.
- File: `src/wallet/injected.ts` — `getInjectedWallet("imToken")` falls back to generic `window.ethereum` only when `isImTokenBrowser()` is true.
- Screenshot evidence: modal shows `state: connecting`, `connected: no`, `address: -`, `qr: -`, and URL `192.168.1.187`.

## Affected Files

- `src/wallet/WalletLoginModal.tsx` — user entry point for mobile imToken login.
- `src/wallet/AutoInjectedLogin.tsx` — auto-login effect for wallet in-app browsers.
- `src/wallet/useWalletConnectLogin.ts` — direct injected login vs WalletConnect fallback selection.
- `src/wallet/injected.ts` — provider/account detection and account request logic.
- `src/wallet/deepLinks.ts` — imToken in-app browser deeplink target.

## Suggested Fix

Do not guess blindly from `connected: no`; first make the runtime state visible. Add a temporary imToken diagnostic surface or alert that reports:

- `navigator.userAgent`
- `location.href`
- whether `window.ethereum` exists
- whether `window.ethereum.providers` exists and its length
- provider flags: `isImToken`, `isMetaMask`, `isTokenPocket`
- result/error of `eth_accounts`
- result/error of `eth_requestAccounts`
- current `isSecureContext`

Then apply one of these fixes based on the diagnostic result:

### Fix Strategy

1. If `window.ethereum` is missing on `192.168.1.187`, test and deploy through an HTTPS domain/tunnel because imToken is likely not injecting on the LAN IP origin.
2. If `window.ethereum` exists but `isImTokenBrowser()` is false, broaden imToken detection or allow a user-selected imToken flow to try generic `window.ethereum` before WalletConnect.
3. If `eth_accounts` is empty and `eth_requestAccounts` errors, surface that wallet error in the modal instead of leaving `state: connecting`.
4. If a valid address is returned, complete imToken login with the local-session path already used by `connectInjectedWallet()` + `localWalletToken()`.
5. Ensure the imToken mobile button never silently falls into WalletConnect when the user is already inside imToken and selected imToken; it should either get an address or show a clear injected-provider/account error.

### Risk Assessment

- Broadly accepting generic `window.ethereum` could pick the wrong provider in multi-wallet browsers. Mitigation: only do this for explicit user selection of imToken or when already inside imToken.
- Testing on LAN IP can produce false negatives. Mitigation: verify on the actual HTTPS domain or an HTTPS tunnel before judging imToken support.
- More diagnostics can expose wallet details on screen. Mitigation: keep diagnostics temporary or behind a debug flag.

## Verification Plan

1. Test in imToken in-app browser on the production HTTPS domain.
2. Test in imToken in-app browser on the current LAN IP to confirm whether `window.ethereum` is missing there.
3. Record diagnostic output for `userAgent`, `hasEthereum`, provider flags, `eth_accounts`, and `eth_requestAccounts`.
4. From Chrome, tap imToken and confirm the in-app browser receives either `?autoLogin=imToken` or the imToken browser fallback runs.
5. Inside imToken, tap wallet login and confirm it does not remain at `state: connecting` without an address.

## Related Issues

- `.unipi/docs/fix/2026-06-04-imtoken-injected-provider-detection-fix.md`
- `.unipi/docs/fix/2026-06-04-imtoken-restore-local-session-login-fix.md`
- `.unipi/docs/fix/2026-06-04-imtoken-auto-login-without-query-fix.md`

## Notes

The current screenshot strongly suggests that the problem is not backend verification or local token writing. The flow never reaches an address. The next useful step is to confirm whether imToken is injecting `window.ethereum` on the tested origin.
