terry-wallet-login #15
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user