From aefe212b2b6a29aaa2be35bc5d5b4aaa6d1da4de Mon Sep 17 00:00:00 2001 From: tuanhqv123 Date: Sat, 17 Jan 2026 13:57:37 +0700 Subject: [PATCH] add zklogin --- .gitignore | 2 + app/layout.tsx | 4 +- components/SuiProviders.tsx | 34 ------------- components/WalletConnectButton.tsx | 13 +++-- components/providers/EnokiProviders.tsx | 68 +++++++++++++++++++++++++ config/enoki.ts | 6 +++ package.json | 2 + 7 files changed, 86 insertions(+), 43 deletions(-) delete mode 100644 components/SuiProviders.tsx create mode 100644 components/providers/EnokiProviders.tsx create mode 100644 config/enoki.ts diff --git a/.gitignore b/.gitignore index fcadec0..669568c 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,5 @@ next-env.d.ts package-lock.json bun.lock +opencode.json +ENOKI_INTEGRATION.md diff --git a/app/layout.tsx b/app/layout.tsx index 4c7ca67..eaa073f 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,6 +1,6 @@ import type { Metadata } from "next"; import { Anton, Inter } from "next/font/google"; -import { SuiProviders } from "@/components/SuiProviders"; +import { EnokiProviders } from "@/components/providers/EnokiProviders"; import "./globals.css"; import "@mysten/dapp-kit/dist/index.css"; @@ -57,7 +57,7 @@ export default function RootLayout({ className={`${anton.variable} ${inter.variable} antialiased`} suppressHydrationWarning > - {children} + {children} ); diff --git a/components/SuiProviders.tsx b/components/SuiProviders.tsx deleted file mode 100644 index 956fea5..0000000 --- a/components/SuiProviders.tsx +++ /dev/null @@ -1,34 +0,0 @@ -"use client"; - -import { createNetworkConfig, SuiClientProvider, WalletProvider } from "@mysten/dapp-kit"; -import { getFullnodeUrl } from "@mysten/sui/client"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { ReactNode, useState } from "react"; - -// Config cho testnet -const { networkConfig } = createNetworkConfig({ - testnet: { url: getFullnodeUrl("testnet") }, - mainnet: { url: getFullnodeUrl("mainnet") }, -}); - -export function SuiProviders({ children }: { children: ReactNode }) { - // Tạo QueryClient trong component để tránh shared state giữa requests - const [queryClient] = useState(() => new QueryClient({ - defaultOptions: { - queries: { - refetchOnWindowFocus: false, - retry: false, - }, - }, - })); - - return ( - - - - {children} - - - - ); -} diff --git a/components/WalletConnectButton.tsx b/components/WalletConnectButton.tsx index eaa6e95..ff6f6e4 100644 --- a/components/WalletConnectButton.tsx +++ b/components/WalletConnectButton.tsx @@ -5,19 +5,18 @@ import { ConnectButton, useCurrentAccount } from "@mysten/dapp-kit"; export function WalletConnectButton() { const account = useCurrentAccount(); - // Format địa chỉ: 0x1234...5678 + // Format address: 0x1234...5678 const formatAddress = (address: string) => { return `${address.slice(0, 6)}...${address.slice(-4)}`; }; return ( - + {account && ( -
- account_balance_wallet +
+ + account_balance_wallet + {formatAddress(account.address)}
)} diff --git a/components/providers/EnokiProviders.tsx b/components/providers/EnokiProviders.tsx new file mode 100644 index 0000000..7353011 --- /dev/null +++ b/components/providers/EnokiProviders.tsx @@ -0,0 +1,68 @@ +"use client"; + +import { ReactNode, useEffect } from "react"; +import { + createNetworkConfig, + SuiClientProvider, + WalletProvider, + useSuiClientContext, +} from "@mysten/dapp-kit"; +import { getFullnodeUrl } from "@mysten/sui/client"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { isEnokiNetwork, registerEnokiWallets } from "@mysten/enoki"; +import { enokiConfig } from "@/config/enoki"; +import "@mysten/dapp-kit/dist/index.css"; + +const { networkConfig } = createNetworkConfig({ + testnet: { url: getFullnodeUrl("testnet") }, + mainnet: { url: getFullnodeUrl("mainnet") }, +}); + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + retry: false, + }, + }, +}); + +function RegisterEnokiWallets() { + const { client, network } = useSuiClientContext(); + + useEffect(() => { + if (!isEnokiNetwork(network)) return; + + const redirectUrl = + typeof window !== "undefined" + ? `${window.location.origin}` + : "http://localhost:3000"; + + const { unregister } = registerEnokiWallets({ + apiKey: enokiConfig.apiKey, + providers: { + google: { + clientId: enokiConfig.googleClientId, + redirectUrl, + }, + }, + client, + network, + }); + + return unregister; + }, [client, network]); + + return null; +} + +export function EnokiProviders({ children }: { children: ReactNode }) { + return ( + + + + {children} + + + ); +} diff --git a/config/enoki.ts b/config/enoki.ts new file mode 100644 index 0000000..67a4c26 --- /dev/null +++ b/config/enoki.ts @@ -0,0 +1,6 @@ +export const enokiConfig = { + apiKey: process.env.NEXT_PUBLIC_ENOKI_API_KEY!, + googleClientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!, + network: (process.env.NEXT_PUBLIC_SUI_NETWORK || "testnet") as "mainnet" | "testnet", + rpcUrl: process.env.NEXT_PUBLIC_SUI_RPC_URL!, +}; diff --git a/package.json b/package.json index 64ff2ad..4e86fd6 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,10 @@ }, "dependencies": { "@mysten/dapp-kit": "^0.20.0", + "@mysten/enoki": "^0.13.0", "@mysten/sui": "^1.45.2", "@tanstack/react-query": "^5.90.18", + "jwt-decode": "^4.0.0", "next": "16.1.3", "react": "19.2.3", "react-dom": "19.2.3"