From a68dd8f616fb6d5466deb116e3dde0559716166d Mon Sep 17 00:00:00 2001 From: TerryM Date: Wed, 3 Jun 2026 00:25:46 +0800 Subject: [PATCH] fix(wallet): complete desktop qr login after approval --- src/wallet/useWalletConnectLogin.ts | 110 ++++++++++++++++------------ 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/src/wallet/useWalletConnectLogin.ts b/src/wallet/useWalletConnectLogin.ts index c74c609..5e6c3be 100644 --- a/src/wallet/useWalletConnectLogin.ts +++ b/src/wallet/useWalletConnectLogin.ts @@ -33,14 +33,6 @@ function metaMaskWalletConnectLink(uri: string): string { return `https://metamask.app.link/wc?uri=${encodeURIComponent(uri)}`; } -function walletConnectQrValue( - kind: WalletKind | undefined, - uri: string, -): string { - if (kind === "metaMask") return metaMaskWalletConnectLink(uri); - return uri; -} - function walletConnectDeeplink( kind: WalletKind | undefined, uri: string, @@ -118,7 +110,7 @@ export function useWalletConnectLogin() { const { address: localAddress, completeLogin } = useWallet(); const { address: wagmiAddress, isConnected: wagmiConnected } = useAccount(); const { connectAsync, connectors } = useConnect(); - const { disconnect, disconnectAsync } = useDisconnect(); + const { disconnectAsync } = useDisconnect(); const [state, setState] = useState("idle"); const [error, setError] = useState(""); const [qrUri, setQrUri] = useState(""); @@ -126,12 +118,15 @@ export function useWalletConnectLogin() { const pendingRef = useRef(false); const completedAddressRef = useRef(null); const cleanupMessageRef = useRef<(() => void) | null>(null); + const cleanupPollingRef = useRef<(() => void) | null>(null); const reset = useCallback(() => { pendingRef.current = false; completedAddressRef.current = null; cleanupMessageRef.current?.(); cleanupMessageRef.current = null; + cleanupPollingRef.current?.(); + cleanupPollingRef.current = null; setState("idle"); setError(""); setQrUri(""); @@ -161,9 +156,7 @@ export function useWalletConnectLogin() { address: wagmiAddress, }); } - - void disconnect(); - }, [completeLogin, disconnect, localAddress, wagmiAddress, wagmiConnected]); + }, [completeLogin, localAddress, wagmiAddress, wagmiConnected]); const start = useCallback( async ( @@ -178,7 +171,11 @@ export function useWalletConnectLogin() { pendingRef.current = true; setState("connecting"); - if (preferredWallet && getInjectedWallet(preferredWallet)) { + if ( + mode === "deeplink" && + preferredWallet && + getInjectedWallet(preferredWallet) + ) { try { const injectedAddress = await connectInjectedWallet(preferredWallet); console.info("[wallet-login] injected connected", { @@ -198,15 +195,20 @@ export function useWalletConnectLogin() { } } - // Prefer the connector RainbowKit created for the selected wallet. This - // is especially important for MetaMask Mobile: RainbowKit/Wagmi use the - // MetaMask SDK connector there instead of the generic WalletConnect one. - const connector = - connectors.find((item) => - connectorMatchesWallet(item, preferredWallet), - ) ?? + // QR mode must always use a WalletConnect-compatible connector so the + // desktop page can render a scannable `wc:` URI instead of opening a + // local browser extension. Deeplink mode can prefer wallet-specific + // connectors (notably MetaMask SDK on mobile). + const walletConnectConnector = connectors.find((item) => item.type === "walletConnect") ?? connectors.find((item) => item.id === "walletConnect"); + const walletSpecificConnector = connectors.find((item) => + connectorMatchesWallet(item, preferredWallet), + ); + const connector = + mode === "qr" + ? walletConnectConnector + : (walletSpecificConnector ?? walletConnectConnector); if (!connector) { pendingRef.current = false; @@ -235,7 +237,7 @@ export function useWalletConnectLogin() { connectorId: connector.id, }); if (mode === "qr") { - setQrUri(walletConnectQrValue(preferredWallet, message.data)); + setQrUri(message.data); } const deeplink = walletConnectDeeplink(preferredWallet, message.data); if (mode === "deeplink" && deeplink && isMobileDevice()) { @@ -248,6 +250,43 @@ export function useWalletConnectLogin() { cleanupMessageRef.current = () => connector.emitter.off("message", onMessage); + cleanupPollingRef.current?.(); + const finishFromAddress = (address: string, source: string) => { + const alreadyCompleted = + completedAddressRef.current?.toLowerCase() === address.toLowerCase(); + if (alreadyCompleted) return; + pendingRef.current = false; + completedAddressRef.current = address; + setConnectedAddress(address); + setQrUri(""); + setState("idle"); + cleanupMessageRef.current?.(); + cleanupMessageRef.current = null; + cleanupPollingRef.current?.(); + cleanupPollingRef.current = null; + console.info("[wallet-login] wallet account connected", { + source, + preferredWallet, + address, + chain: "BNB Chain", + chainId: bsc.id, + }); + completeLogin(localWalletToken(address), address); + console.info("[wallet-login] local wallet session completed", { + address, + }); + }; + const pollId = window.setInterval(() => { + void connector + .getAccounts() + .then((accounts) => { + const account = accounts[0]; + if (account) finishFromAddress(account, "connector-poll"); + }) + .catch(() => undefined); + }, 1000); + cleanupPollingRef.current = () => window.clearInterval(pollId); + try { await disconnectAsync().catch(() => undefined); await connector.disconnect().catch(() => undefined); @@ -255,23 +294,9 @@ export function useWalletConnectLogin() { const connectedAddress = result.accounts[0]; if (!connectedAddress) throw new Error("Wallet connected without an account"); - pendingRef.current = false; - completedAddressRef.current = connectedAddress; - setConnectedAddress(connectedAddress); - console.info("[wallet-login] walletconnect connected", { - address: connectedAddress, - chain: "BNB Chain", - chainId: bsc.id, - }); - window.alert(`扫码成功,已拿到钱包地址:\n${connectedAddress}`); - completeLogin(localWalletToken(connectedAddress), connectedAddress); - console.info("[wallet-login] local wallet session completed", { - address: connectedAddress, - }); - setQrUri(""); - setState("idle"); - disconnect(); + finishFromAddress(connectedAddress, "connectAsync"); } catch (err) { + if (completedAddressRef.current) return; pendingRef.current = false; setState("idle"); setError( @@ -279,16 +304,11 @@ export function useWalletConnectLogin() { ); cleanupMessageRef.current?.(); cleanupMessageRef.current = null; + cleanupPollingRef.current?.(); + cleanupPollingRef.current = null; } }, - [ - available, - completeLogin, - connectAsync, - connectors, - disconnect, - disconnectAsync, - ], + [available, completeLogin, connectAsync, connectors, disconnectAsync], ); return {