terry-wallet-login #15

Merged
terry merged 95 commits from terry-wallet-login into terry-staging 2026-06-05 16:32:43 +00:00
Showing only changes of commit a68dd8f616 - Show all commits

View File

@@ -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<WalletConnectLoginState>("idle");
const [error, setError] = useState("");
const [qrUri, setQrUri] = useState("");
@@ -126,12 +118,15 @@ export function useWalletConnectLogin() {
const pendingRef = useRef(false);
const completedAddressRef = useRef<string | null>(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 {