diff --git a/.unipi/docs/fix/2026-06-06-imtoken-production-address-fix.md b/.unipi/docs/fix/2026-06-06-imtoken-production-address-fix.md new file mode 100644 index 0000000..a91292a --- /dev/null +++ b/.unipi/docs/fix/2026-06-06-imtoken-production-address-fix.md @@ -0,0 +1,34 @@ +--- +title: "imToken production cannot get wallet address — Quick Fix" +type: quick-fix +date: 2026-06-06 +--- + +# imToken production cannot get wallet address — Quick Fix + +## Bug + +`main` serves `ark-library.com`, while `terry-wallet-login` serves the staging site. Staging can log in with imToken, but production can open imToken's in-app browser without getting the wallet address or completing login. + +## Root Cause + +The auto-login effect only ran when the URL contained an explicit `autoLogin` / `autologin` query parameter. imToken's in-app-browser deeplink can open the DApp page without preserving that query string. In that case the production page was inside imToken and could have an injected wallet provider, but `AutoInjectedLogin` returned early and never attempted to read the wallet address. + +The parser was also case-sensitive, so a lowercase `autologin=imtoken` test URL would not start the flow. + +## Fix + +Updated the auto-login entrypoint to treat an imToken in-app-browser user agent as an imToken direct-login session even when the query parameter is missing. Also made the wallet-kind parser case-insensitive. + +### Files Modified + +- `src/wallet/AutoInjectedLogin.tsx` — imports `isImTokenBrowser()`, falls back to `imToken` when inside imToken without an auto-login query, and accepts lowercase wallet kind values. + +## Verification + +- `npx prettier --write src/wallet/AutoInjectedLogin.tsx` +- `npx tsc --noEmit` + +## Notes + +This is scoped to imToken UA fallback. TokenPocket and MetaMask still require an explicit auto-login query parameter. diff --git a/src/wallet/AutoInjectedLogin.tsx b/src/wallet/AutoInjectedLogin.tsx index 4191d6d..3324cd7 100644 --- a/src/wallet/AutoInjectedLogin.tsx +++ b/src/wallet/AutoInjectedLogin.tsx @@ -2,6 +2,7 @@ import { useEffect } from "react"; import { connectInjectedWallet, getInjectedWallet, + isImTokenBrowser, type WalletKind, } from "./injected"; import { useWallet } from "./WalletProvider"; @@ -11,18 +12,23 @@ const ETHEREUM_WAIT_MS = 8000; const ETHEREUM_POLL_MS = 200; function parseKind(value: string | null): WalletKind | null { - if (value === "tokenPocket" || value === "metaMask" || value === "imToken") { - return value; - } + const normalized = value?.toLowerCase(); + if (normalized === "tokenpocket") return "tokenPocket"; + if (normalized === "metamask") return "metaMask"; + if (normalized === "imtoken") return "imToken"; return null; } -function autoLoginKindFromParams(params: URLSearchParams): WalletKind | null { +function autoLoginKind(params: URLSearchParams): WalletKind | null { for (const key of AUTO_LOGIN_PARAMS) { const kind = parseKind(params.get(key)); if (kind) return kind; } - return null; + return isImTokenBrowser() ? "imToken" : null; +} + +function hasAutoLoginParam(params: URLSearchParams): boolean { + return AUTO_LOGIN_PARAMS.some((key) => params.has(key)); } function stripAutoLoginParam(): void { @@ -57,10 +63,10 @@ export function AutoInjectedLogin() { useEffect(() => { if (typeof window === "undefined") return; const params = new URLSearchParams(window.location.search); - const kind = autoLoginKindFromParams(params); + const kind = autoLoginKind(params); if (!kind) return; - stripAutoLoginParam(); + if (hasAutoLoginParam(params)) stripAutoLoginParam(); if (status === "loggedIn") return; let cancelled = false;