import { useEffect } from "react"; import { connectInjectedWallet, getInjectedWallet, type WalletKind, } from "./injected"; import { localWalletToken, useWallet } from "./WalletProvider"; const AUTO_LOGIN_PARAM = "autoLogin"; 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; } return null; } function stripAutoLoginParam(): void { const url = new URL(window.location.href); url.searchParams.delete(AUTO_LOGIN_PARAM); const qs = url.searchParams.toString(); const next = url.pathname + (qs ? `?${qs}` : "") + url.hash; window.history.replaceState({}, "", next); } function waitForInjected(kind: WalletKind): Promise { return new Promise((resolve) => { const start = Date.now(); const tick = () => { if (getInjectedWallet(kind)) { resolve(true); return; } if (Date.now() - start >= ETHEREUM_WAIT_MS) { resolve(false); return; } window.setTimeout(tick, ETHEREUM_POLL_MS); }; tick(); }); } /** * When the page is opened via a `?autoLogin=` deeplink (typically from * inside TokenPocket / imToken in-app browsers), wait for the wallet to inject * `window.ethereum`, then complete a local wallet session automatically. Bypasses * WalletConnect entirely so it works on networks where the WC relay is blocked. */ export function AutoInjectedLogin() { const { completeLogin, status } = useWallet(); useEffect(() => { if (typeof window === "undefined") return; const params = new URLSearchParams(window.location.search); const kind = parseKind(params.get(AUTO_LOGIN_PARAM)); if (!kind) return; stripAutoLoginParam(); if (status === "loggedIn") return; let cancelled = false; void waitForInjected(kind).then(async (ready) => { if (cancelled || !ready) return; try { const address = await connectInjectedWallet(kind); if (cancelled) return; completeLogin(localWalletToken(address), address); } catch (err) { // eslint-disable-next-line no-console console.warn("[wallet-autologin] failed", err); } }); return () => { cancelled = true; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return null; }