fix(wallet): restore metamask mobile login
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useRef, useState } from "react";
|
||||
import { useConnect, useDisconnect } from "wagmi";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useAccount, useConnect, useDisconnect } from "wagmi";
|
||||
import { bsc } from "wagmi/chains";
|
||||
import { hasWalletConnectProjectId } from "./RainbowWalletProvider";
|
||||
import {
|
||||
@@ -24,18 +24,39 @@ function currentUrl(): string {
|
||||
return window.location.href;
|
||||
}
|
||||
|
||||
function isWalletConnectUri(uri: string): boolean {
|
||||
return uri.startsWith("wc:");
|
||||
}
|
||||
|
||||
function metaMaskWalletConnectLink(uri: string): string {
|
||||
if (!isWalletConnectUri(uri)) return uri;
|
||||
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,
|
||||
): string | null {
|
||||
if (kind === "tokenPocket") {
|
||||
return `tpoutside://wc?uri=${encodeURIComponent(uri)}`;
|
||||
return isWalletConnectUri(uri)
|
||||
? `tpoutside://wc?uri=${encodeURIComponent(uri)}`
|
||||
: uri;
|
||||
}
|
||||
if (kind === "metaMask") {
|
||||
return `https://metamask.app.link/wc?uri=${encodeURIComponent(uri)}`;
|
||||
return metaMaskWalletConnectLink(uri);
|
||||
}
|
||||
if (kind === "imToken") {
|
||||
return `imtokenv2://wc?uri=${encodeURIComponent(uri)}`;
|
||||
return isWalletConnectUri(uri)
|
||||
? `imtokenv2://wc?uri=${encodeURIComponent(uri)}`
|
||||
: uri;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -61,6 +82,26 @@ function openWalletDeeplink(
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
function connectorMatchesWallet(
|
||||
connector: { id: string; name?: string; type?: string },
|
||||
kind: WalletKind | undefined,
|
||||
): boolean {
|
||||
if (!kind) return false;
|
||||
const id = connector.id.toLowerCase();
|
||||
const name = connector.name?.toLowerCase() ?? "";
|
||||
const type = connector.type?.toLowerCase() ?? "";
|
||||
if (kind === "metaMask") {
|
||||
return id === "metamask" || type === "metamask" || name === "metamask";
|
||||
}
|
||||
if (kind === "tokenPocket") {
|
||||
return id === "tokenpocket" || name === "tokenpocket";
|
||||
}
|
||||
if (kind === "imToken") {
|
||||
return id === "imtoken" || name === "imtoken";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* MetaMask / imToken QR fallback via RainbowKit + WalletConnect.
|
||||
*
|
||||
@@ -74,7 +115,8 @@ function openWalletDeeplink(
|
||||
*/
|
||||
export function useWalletConnectLogin() {
|
||||
const available = hasWalletConnectProjectId();
|
||||
const { completeLogin } = useWallet();
|
||||
const { address: localAddress, completeLogin } = useWallet();
|
||||
const { address: wagmiAddress, isConnected: wagmiConnected } = useAccount();
|
||||
const { connectAsync, connectors } = useConnect();
|
||||
const { disconnect, disconnectAsync } = useDisconnect();
|
||||
const [state, setState] = useState<WalletConnectLoginState>("idle");
|
||||
@@ -82,10 +124,12 @@ export function useWalletConnectLogin() {
|
||||
const [qrUri, setQrUri] = useState("");
|
||||
const [connectedAddress, setConnectedAddress] = useState("");
|
||||
const pendingRef = useRef(false);
|
||||
const completedAddressRef = useRef<string | null>(null);
|
||||
const cleanupMessageRef = useRef<(() => void) | null>(null);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
pendingRef.current = false;
|
||||
completedAddressRef.current = null;
|
||||
cleanupMessageRef.current?.();
|
||||
cleanupMessageRef.current = null;
|
||||
setState("idle");
|
||||
@@ -94,6 +138,33 @@ export function useWalletConnectLogin() {
|
||||
setConnectedAddress("");
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!wagmiConnected || !wagmiAddress) return;
|
||||
const alreadyCompleted =
|
||||
completedAddressRef.current?.toLowerCase() === wagmiAddress.toLowerCase();
|
||||
if (alreadyCompleted) return;
|
||||
|
||||
completedAddressRef.current = wagmiAddress;
|
||||
pendingRef.current = false;
|
||||
setConnectedAddress(wagmiAddress);
|
||||
setQrUri("");
|
||||
setState("idle");
|
||||
|
||||
if (localAddress?.toLowerCase() !== wagmiAddress.toLowerCase()) {
|
||||
console.info("[wallet-login] wagmi account connected", {
|
||||
address: wagmiAddress,
|
||||
chain: "BNB Chain",
|
||||
chainId: bsc.id,
|
||||
});
|
||||
completeLogin(localWalletToken(wagmiAddress), wagmiAddress);
|
||||
console.info("[wallet-login] local wallet session completed", {
|
||||
address: wagmiAddress,
|
||||
});
|
||||
}
|
||||
|
||||
void disconnect();
|
||||
}, [completeLogin, disconnect, localAddress, wagmiAddress, wagmiConnected]);
|
||||
|
||||
const start = useCallback(
|
||||
async (
|
||||
preferredWallet?: WalletKind,
|
||||
@@ -103,6 +174,7 @@ export function useWalletConnectLogin() {
|
||||
setError("");
|
||||
setQrUri("");
|
||||
setConnectedAddress("");
|
||||
completedAddressRef.current = null;
|
||||
pendingRef.current = true;
|
||||
setState("connecting");
|
||||
|
||||
@@ -126,9 +198,13 @@ export function useWalletConnectLogin() {
|
||||
}
|
||||
}
|
||||
|
||||
// This modal is QR/WalletConnect-only. RainbowKit also exposes wallet-
|
||||
// specific injected connectors (for example `tokenPocket`) when an
|
||||
// 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),
|
||||
) ??
|
||||
connectors.find((item) => item.type === "walletConnect") ??
|
||||
connectors.find((item) => item.id === "walletConnect");
|
||||
|
||||
@@ -158,7 +234,9 @@ export function useWalletConnectLogin() {
|
||||
preferredWallet,
|
||||
connectorId: connector.id,
|
||||
});
|
||||
if (mode === "qr") setQrUri(message.data);
|
||||
if (mode === "qr") {
|
||||
setQrUri(walletConnectQrValue(preferredWallet, message.data));
|
||||
}
|
||||
const deeplink = walletConnectDeeplink(preferredWallet, message.data);
|
||||
if (mode === "deeplink" && deeplink && isMobileDevice()) {
|
||||
openWalletDeeplink(preferredWallet, deeplink);
|
||||
@@ -178,6 +256,7 @@ export function useWalletConnectLogin() {
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user