diff --git a/apps/wallet-ui/src/app/[ecosystem]/(ui)/layout.tsx b/apps/wallet-ui/src/app/[ecosystem]/(authed)/layout.tsx similarity index 100% rename from apps/wallet-ui/src/app/[ecosystem]/(ui)/layout.tsx rename to apps/wallet-ui/src/app/[ecosystem]/(authed)/layout.tsx diff --git a/apps/wallet-ui/src/app/[ecosystem]/(ui)/wallet/[address]/layout.tsx b/apps/wallet-ui/src/app/[ecosystem]/(authed)/wallet/[address]/layout.tsx similarity index 86% rename from apps/wallet-ui/src/app/[ecosystem]/(ui)/wallet/[address]/layout.tsx rename to apps/wallet-ui/src/app/[ecosystem]/(authed)/wallet/[address]/layout.tsx index 0b1b35c428d..735bbdd557c 100644 --- a/apps/wallet-ui/src/app/[ecosystem]/(ui)/wallet/[address]/layout.tsx +++ b/apps/wallet-ui/src/app/[ecosystem]/(authed)/wallet/[address]/layout.tsx @@ -1,11 +1,9 @@ import { ChainCombobox } from "@/components/ChainCombobox"; -import { getCurrentUser } from "@/lib/auth"; import { getChains } from "@/lib/chains"; import { client } from "@/lib/client"; import { getEcosystemInfo } from "@/lib/ecosystems"; import { SIMPLEHASH_NFT_SUPPORTED_CHAIN_IDS } from "@/util/simplehash"; import type { Metadata, ResolvingMetadata } from "next"; -import { redirect } from "next/navigation"; import { resolveName } from "thirdweb/extensions/ens"; import { shortenAddress } from "thirdweb/utils"; @@ -34,23 +32,17 @@ export default async function Layout({ children: React.ReactNode; params: { ecosystem: string; address: string }; }) { - const userAddressPromise = getCurrentUser(); const ensPromise = resolveName({ client, address: params.address, }); const thirdwebChainsPromise = getChains(); - const [userAddress, ens, thirdwebChains] = await Promise.all([ - userAddressPromise, + const [ens, thirdwebChains] = await Promise.all([ ensPromise, thirdwebChainsPromise, ]); - if (userAddress !== params.address) { - redirect(`/wallet/${userAddress}`); - } - const simpleHashChains = thirdwebChains.filter((chain) => SIMPLEHASH_NFT_SUPPORTED_CHAIN_IDS.includes(chain.chainId), ); diff --git a/apps/wallet-ui/src/app/[ecosystem]/(ui)/wallet/[address]/loading.tsx b/apps/wallet-ui/src/app/[ecosystem]/(authed)/wallet/[address]/loading.tsx similarity index 100% rename from apps/wallet-ui/src/app/[ecosystem]/(ui)/wallet/[address]/loading.tsx rename to apps/wallet-ui/src/app/[ecosystem]/(authed)/wallet/[address]/loading.tsx diff --git a/apps/wallet-ui/src/app/[ecosystem]/(authed)/wallet/[address]/page.tsx b/apps/wallet-ui/src/app/[ecosystem]/(authed)/wallet/[address]/page.tsx new file mode 100644 index 00000000000..5438a916a3b --- /dev/null +++ b/apps/wallet-ui/src/app/[ecosystem]/(authed)/wallet/[address]/page.tsx @@ -0,0 +1,18 @@ +import { AutoConnectWalletConnect } from "@/components/AutoConnectWalletConnect"; +import NftGallery from "@/components/NftGallery"; +import { getAddress } from "thirdweb"; + +export default function Page({ + params: { address }, + searchParams: { chainId, uri }, +}: { + params: { address: string }; + searchParams: { chainId?: string; uri?: string }; +}) { + return ( + <> + + + + ); +} diff --git a/apps/wallet-ui/src/app/[ecosystem]/(ui)/wallet/[address]/page.tsx b/apps/wallet-ui/src/app/[ecosystem]/(ui)/wallet/[address]/page.tsx deleted file mode 100644 index 10228f3c0a3..00000000000 --- a/apps/wallet-ui/src/app/[ecosystem]/(ui)/wallet/[address]/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import NftGallery from "@/components/NftGallery"; -import { getAddress } from "thirdweb"; - -export default async function Page({ - params: { address }, - searchParams: { chainId }, -}: { - params: { address: string }; - searchParams: { chainId: string }; -}) { - return ; -} diff --git a/apps/wallet-ui/src/app/[ecosystem]/login/layout.tsx b/apps/wallet-ui/src/app/[ecosystem]/login/layout.tsx index 0c9e87c22e1..c28be22248f 100644 --- a/apps/wallet-ui/src/app/[ecosystem]/login/layout.tsx +++ b/apps/wallet-ui/src/app/[ecosystem]/login/layout.tsx @@ -5,9 +5,7 @@ export default async function Layout({ children, }: { children: React.ReactNode }) { const userAddress = await getCurrentUser(); - console.log("userAddress", userAddress); if (userAddress) { - console.log("redirecting to wallet", userAddress); redirect(`/wallet/${userAddress}`); } diff --git a/apps/wallet-ui/src/app/[ecosystem]/login/page.tsx b/apps/wallet-ui/src/app/[ecosystem]/login/page.tsx index 19f35213c97..e8b397b8066 100644 --- a/apps/wallet-ui/src/app/[ecosystem]/login/page.tsx +++ b/apps/wallet-ui/src/app/[ecosystem]/login/page.tsx @@ -1,33 +1,5 @@ -"use client"; -import { generatePayload, getCurrentUser, login, logout } from "@/lib/auth"; -import { client } from "@/lib/client"; -import { useTheme } from "next-themes"; -import { useRouter } from "next/navigation"; -import type { VerifyLoginPayloadParams } from "thirdweb/auth"; -import { ConnectEmbed } from "thirdweb/react"; -import { ecosystemWallet } from "thirdweb/wallets"; +import { ConnectEmbed } from "@/components/ConnectEmbed"; -export default function Page({ params }: { params: { ecosystem: string } }) { - const { theme } = useTheme(); - const router = useRouter(); - - return ( - { - const success = await login(loginParams); - if (success) { - router.push(`/wallet/${loginParams.payload.address}`); - } - }, - isLoggedIn: async () => !!(await getCurrentUser()), - doLogout: logout, - }} - /> - ); +export default function Page() { + return ; } diff --git a/apps/wallet-ui/src/app/[ecosystem]/wc/page.tsx b/apps/wallet-ui/src/app/[ecosystem]/wc/page.tsx new file mode 100644 index 00000000000..19a8a9fb1f0 --- /dev/null +++ b/apps/wallet-ui/src/app/[ecosystem]/wc/page.tsx @@ -0,0 +1,17 @@ +// This page is to accept a Wallet Connect request +import { getCurrentUser } from "@/lib/auth"; +import { redirect } from "next/navigation"; + +export default async function Page({ + searchParams: { uri }, +}: { + searchParams: { uri: string }; +}) { + const currentUser = await getCurrentUser(); + + if (!currentUser) { + redirect(`/login?uri=${encodeURIComponent(uri)}`); + } + + redirect(`/wallet/${currentUser}?uri=${encodeURIComponent(uri)}`); +} diff --git a/apps/wallet-ui/src/components/AutoConnectWalletConnect.tsx b/apps/wallet-ui/src/components/AutoConnectWalletConnect.tsx new file mode 100644 index 00000000000..d1fe09e61da --- /dev/null +++ b/apps/wallet-ui/src/components/AutoConnectWalletConnect.tsx @@ -0,0 +1,8 @@ +"use client"; + +import { useWalletConnect } from "@/hooks/useWalletConnect"; + +export function AutoConnectWalletConnect({ uri }: { uri?: string }) { + useWalletConnect({ uri }); + return <>; +} diff --git a/apps/wallet-ui/src/components/ConnectButton.tsx b/apps/wallet-ui/src/components/ConnectButton.tsx index eb25c3e0bf4..e5cb72e0338 100644 --- a/apps/wallet-ui/src/components/ConnectButton.tsx +++ b/apps/wallet-ui/src/components/ConnectButton.tsx @@ -1,5 +1,4 @@ "use client"; -import { generatePayload, isLoggedIn, login, logout } from "@/lib/auth"; import { client } from "@/lib/client"; import { useTheme } from "next-themes"; import { @@ -24,14 +23,6 @@ export default function ConnectButton({ wallets={[ecosystemWallet(ecosystem)]} client={client} theme={theme === "light" ? "light" : "dark"} - auth={{ - getLoginPayload: generatePayload, - doLogin: async (p) => { - login(p); - }, - isLoggedIn, - doLogout: logout, - }} /> ); } diff --git a/apps/wallet-ui/src/components/ConnectEmbed.tsx b/apps/wallet-ui/src/components/ConnectEmbed.tsx new file mode 100644 index 00000000000..e40a2031004 --- /dev/null +++ b/apps/wallet-ui/src/components/ConnectEmbed.tsx @@ -0,0 +1,37 @@ +"use client"; +import { generatePayload, getCurrentUser, login, logout } from "@/lib/auth"; +import { client } from "@/lib/client"; +import { useTheme } from "next-themes"; +import { useParams, useRouter, useSearchParams } from "next/navigation"; +import type { VerifyLoginPayloadParams } from "thirdweb/auth"; +import { ConnectEmbed as ThirdwebConnectEmbed } from "thirdweb/react"; +import { ecosystemWallet } from "thirdweb/wallets"; + +export function ConnectEmbed() { + const { theme } = useTheme(); + const router = useRouter(); + const params = useParams(); + const searchParams = useSearchParams(); + + return ( + { + const success = await login(loginParams); + if (success) { + router.push( + `/wallet/${loginParams.payload.address}?${searchParams.toString()}`, + ); + } + }, + isLoggedIn: async () => !!(await getCurrentUser()), + doLogout: logout, + }} + /> + ); +} diff --git a/apps/wallet-ui/src/hooks/useWalletConnect.tsx b/apps/wallet-ui/src/hooks/useWalletConnect.tsx new file mode 100644 index 00000000000..e064e4111ca --- /dev/null +++ b/apps/wallet-ui/src/hooks/useWalletConnect.tsx @@ -0,0 +1,40 @@ +import { client } from "@/lib/client"; +import { useQuery } from "@tanstack/react-query"; +import { CheckIcon } from "lucide-react"; +import { toast } from "sonner"; +import { useActiveWallet } from "thirdweb/react"; +import { + createWalletConnectClient, + createWalletConnectSession, +} from "thirdweb/wallets"; + +export function useWalletConnect({ uri }: { uri?: string }) { + const wallet = useActiveWallet(); + + useQuery({ + queryKey: ["wallet-connect", uri], + queryFn: async () => { + if (!wallet || !uri) throw new Error("Unreachable"); + const wcClient = await createWalletConnectClient({ + wallet: wallet, + client: client, + }); + + createWalletConnectSession({ + walletConnectClient: wcClient, + uri, + }); + + toast.success("Wallet connected.", { + id: "wallet-connect", + icon: , + duration: 5000, + }); + + return true; + }, + enabled: !!uri || !!wallet, + }); + + return; +} diff --git a/packages/thirdweb/src/wallets/wallet-connect/receiver/index.ts b/packages/thirdweb/src/wallets/wallet-connect/receiver/index.ts index 16722082cf2..ca9df6aa3d6 100644 --- a/packages/thirdweb/src/wallets/wallet-connect/receiver/index.ts +++ b/packages/thirdweb/src/wallets/wallet-connect/receiver/index.ts @@ -284,7 +284,7 @@ export async function createWalletConnectClient( * client: client, * }); * - * const session = await createWalletConnectSession({ + * const session = createWalletConnectSession({ * walletConnectClient: client, * uri: "wc:...", * }); diff --git a/packages/thirdweb/src/wallets/wallet-connect/receiver/session-request.ts b/packages/thirdweb/src/wallets/wallet-connect/receiver/session-request.ts index d07964ffe4c..c3903a48861 100644 --- a/packages/thirdweb/src/wallets/wallet-connect/receiver/session-request.ts +++ b/packages/thirdweb/src/wallets/wallet-connect/receiver/session-request.ts @@ -1,6 +1,12 @@ import type { ThirdwebClient } from "../../../client/client.js"; import type { Hex } from "../../../utils/encoding/hex.js"; import type { Wallet } from "../../interfaces/wallet.js"; +import { handleSendRawTransactionRequest } from "./request-handlers/send-raw-transaction.js"; +import { handleSendTransactionRequest } from "./request-handlers/send-transaction.js"; +import { handleSignTransactionRequest } from "./request-handlers/sign-transaction.js"; +import { handleSignTypedDataRequest } from "./request-handlers/sign-typed-data.js"; +// Due to some edge cases, we can't import these handlers dynamically +import { handleSignRequest } from "./request-handlers/sign.js"; import type { WalletConnectAddEthereumChainRequestParams, WalletConnectClient, @@ -54,9 +60,6 @@ export async function fulfillRequest(options: { params: request.params as WalletConnectSignRequestPrams, }); } else { - const { handleSignRequest } = await import( - "./request-handlers/sign.js" - ); result = await handleSignRequest({ account, params: request.params as WalletConnectSignRequestPrams, @@ -71,9 +74,6 @@ export async function fulfillRequest(options: { params: request.params as WalletConnectSignRequestPrams, }); } else { - const { handleSignRequest } = await import( - "./request-handlers/sign.js" - ); result = await handleSignRequest({ account, params: request.params as WalletConnectSignRequestPrams, @@ -88,9 +88,6 @@ export async function fulfillRequest(options: { params: request.params as WalletConnectSignTypedDataRequestParams, }); } else { - const { handleSignTypedDataRequest } = await import( - "./request-handlers/sign-typed-data.js" - ); result = await handleSignTypedDataRequest({ account, params: request.params as WalletConnectSignTypedDataRequestParams, @@ -105,9 +102,6 @@ export async function fulfillRequest(options: { params: request.params as WalletConnectSignTypedDataRequestParams, }); } else { - const { handleSignTypedDataRequest } = await import( - "./request-handlers/sign-typed-data.js" - ); result = await handleSignTypedDataRequest({ account, params: request.params as WalletConnectSignTypedDataRequestParams, @@ -122,9 +116,6 @@ export async function fulfillRequest(options: { params: request.params as WalletConnectTransactionRequestParams, }); } else { - const { handleSignTransactionRequest } = await import( - "./request-handlers/sign-transaction.js" - ); result = await handleSignTransactionRequest({ account, params: request.params as WalletConnectTransactionRequestParams, @@ -141,10 +132,6 @@ export async function fulfillRequest(options: { params: request.params as WalletConnectTransactionRequestParams, }); } else { - const { handleSendTransactionRequest } = await import( - "./request-handlers/send-transaction.js" - ); - result = await handleSendTransactionRequest({ account, chainId, @@ -163,10 +150,6 @@ export async function fulfillRequest(options: { params: request.params as WalletConnectRawTransactionRequestParams, }); } else { - const { handleSendRawTransactionRequest } = await import( - "./request-handlers/send-raw-transaction.js" - ); - result = await handleSendRawTransactionRequest({ account, chainId,