From c9a5cd25932d65c302e6ea6cad05cf6369c09552 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sat, 8 Nov 2025 09:54:06 +0000 Subject: [PATCH] Create Web3Callback.tsx - Handle Ethereum signature verification cgen-9c81cac1a6b041b5b628da737e320175 --- client/pages/Web3Callback.tsx | 105 ++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 client/pages/Web3Callback.tsx diff --git a/client/pages/Web3Callback.tsx b/client/pages/Web3Callback.tsx new file mode 100644 index 00000000..af848272 --- /dev/null +++ b/client/pages/Web3Callback.tsx @@ -0,0 +1,105 @@ +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { useWeb3 } from "@/contexts/Web3Context"; +import { useAuth } from "@/contexts/AuthContext"; +import { useAethexToast } from "@/hooks/use-aethex-toast"; +import LoadingScreen from "@/components/LoadingScreen"; + +export default function Web3Callback() { + const navigate = useNavigate(); + const { account, signMessage } = useWeb3(); + const { user, loading: authLoading } = useAuth(); + const { error: toastError, success: toastSuccess } = useAethexToast(); + const [isProcessing, setIsProcessing] = useState(false); + + useEffect(() => { + const handleWeb3Auth = async () => { + if (!account || authLoading) return; + + setIsProcessing(true); + try { + // Generate a nonce from the backend + const nonceResponse = await fetch("/api/web3/nonce", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ wallet_address: account }), + }); + + if (!nonceResponse.ok) { + throw new Error("Failed to generate nonce"); + } + + const { nonce } = await nonceResponse.json(); + + // Create message to sign + const message = `Sign this message to authenticate with AeThex\n\nWallet: ${account}\nNonce: ${nonce}`; + + // Request signature + const signature = await signMessage(message); + + // Verify signature on backend and create/link account + const verifyResponse = await fetch("/api/web3/verify", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + wallet_address: account, + signature, + message, + nonce, + }), + }); + + if (!verifyResponse.ok) { + const errorData = await verifyResponse.json(); + throw new Error(errorData.error || "Verification failed"); + } + + const data = await verifyResponse.json(); + + // If user is already authenticated, link the wallet + if (user && data.success) { + toastSuccess({ + title: "Wallet linked", + description: "Your Ethereum wallet is now connected to your account", + }); + navigate("/dashboard?tab=connections"); + return; + } + + // Otherwise, create account and sign in + if (data.auth_token) { + // Backend will handle session creation + toastSuccess({ + title: "Web3 authentication successful", + description: "Redirecting to dashboard...", + }); + navigate("/dashboard"); + return; + } + + navigate("/onboarding?web3_wallet=" + account); + } catch (error: any) { + console.error("Web3 auth error:", error); + toastError({ + title: "Web3 authentication failed", + description: error?.message || "Could not authenticate with wallet", + }); + navigate("/login"); + } finally { + setIsProcessing(false); + } + }; + + if (account && !authLoading) { + handleWeb3Auth(); + } + }, [account, authLoading, signMessage, user, navigate, toastError, toastSuccess]); + + return ( + + ); +}