diff --git a/src/components/Charts/ClaimChart/index.tsx b/src/components/Charts/ClaimChart/index.tsx index 37b6016..132c108 100644 --- a/src/components/Charts/ClaimChart/index.tsx +++ b/src/components/Charts/ClaimChart/index.tsx @@ -2,7 +2,7 @@ import { ChartCard } from "./ChartCard"; import { ClaimData } from "@/types"; import { depth, shortenAddress } from "@/utils"; import { EChartOption } from "echarts"; -import React, { FC, useState } from "react"; +import React, { FC, useEffect, useMemo, useState } from "react"; import { Dialog, DialogBackdrop, @@ -13,7 +13,12 @@ import { ConnectButton } from "@rainbow-me/rainbowkit"; import { Button } from "@/components/Button"; import { Input } from "@/components/Input"; import { useCalculateClaim } from "@/hooks/useCaculateClaim"; -import { useWriteContract } from "wagmi"; +import { useReadContract, useWriteContract } from "wagmi"; +import { abi } from "@/utils/abi"; +import { Abi, Address, Chain, Client, Transport, formatUnits, parseUnits } from "viem"; +import { useNetworkConfig } from "@/hooks/useNetworkConfig"; +import { waitForTransactionReceipt } from "viem/actions"; +import { useWagmiConfig } from "@/hooks/useWagmiConfig"; const xGap = 45; const yGap = 50; @@ -126,7 +131,7 @@ const genNodesAndLinks = (data: ClaimData[]): any => { }; }; -const ClaimChart: FC<{ claimData: ClaimData[] }> = ({ claimData }) => { +const ClaimChart: FC<{ claimData: ClaimData[], address: string }> = ({ claimData, address }) => { const { nodes, links, maxDepth } = genNodesAndLinks(claimData); const { isMutating, trigger } = useCalculateClaim(); const options: EChartOption = { @@ -185,14 +190,89 @@ const ClaimChart: FC<{ claimData: ClaimData[] }> = ({ claimData }) => { const [showModal, setShowModal] = useState(false); const [modalData, setModalData] = useState(); const [val, setVal] = useState(""); - const { writeContract } = useWriteContract(); + const [recommendAttackClaim, setAttackClaim] = useState("") + const [recommendDefendClaim, setDefendClaim] = useState("") + const config = useWagmiConfig() + const attackPosition = useMemo(() => { + if (modalData) { + return 2 * Number(modalData.position) + } + }, [modalData]) + const defendPosition = useMemo(() => { + if (modalData) { + return 2 * (Number(modalData.position) + 1) + } + }, [modalData]) + const { writeContractAsync } = useWriteContract(); + const { data: index } = useReadContract({ + abi: abi as Abi, + address: address as Address, + functionName: 'claimDataLen' + }) + const { data: attackGas } = useReadContract({ + abi: abi as Abi, + address: address as Address, + functionName: 'getRequiredBond', + args: [attackPosition] + }) + const { data: defendGas } = useReadContract({ + abi: abi as Abi, + address: address as Address, + functionName: 'getRequiredBond', + args: [defendPosition] + }) const handleClick = (e: any) => { setShowModal(true); setModalData(e.data); }; - const handleAttack = async () => {}; + useEffect(() => { + if (attackPosition) { + trigger({ disputeGame: address, position: attackPosition }).then((res) => { + setAttackClaim(res.claims) + }) + } + }, [attackPosition]) + useEffect(() => { + if (defendPosition) { + trigger({ disputeGame: address, position: defendPosition }).then((res) => { + setDefendClaim(res.claims) + }) + + } + }, [defendPosition]) + + const handleAttack = async () => { + if (!val) return; + if (!index) return; + if (!attackGas) return; + const hash = await writeContractAsync({ + abi: abi as Abi, + address: address as Address, + functionName: 'attack', + args: ['0x' + modalData?.claim, Number(index) - 1, val], + value: parseUnits(formatUnits(attackGas as bigint, 18), 18) + }) + const res = await waitForTransactionReceipt(config as any, { hash }) + console.log(res, 'res-defend') + }; + + const handleDefend = async () => { + if (!val) return; + if (!index) return; + if (!attackGas) return; + console.log(['0x' + modalData?.claim, Number(index) - 1, val]) + const hash = await writeContractAsync({ + abi: abi as Abi, + address: address as Address, + functionName: 'defend', + args: ['0x' + modalData?.claim, Number(index) - 1, val], + value: parseUnits(formatUnits(defendGas as bigint, 18), 18) + }) + console.log(hash, 'hash') + + } return ( <> @@ -215,13 +295,27 @@ const ClaimChart: FC<{ claimData: ClaimData[] }> = ({ claimData }) => { Challenge -

+

- Claim + Claim:
- {modalData?.claim} + {'0x' + modalData?.claim} +
+
+
+ Recommend Attack Claim: +
+
+ {recommendAttackClaim} +
+
+
+ Recommend Defend Claim: +
+
+ {recommendDefendClaim}
@@ -234,21 +328,21 @@ const ClaimChart: FC<{ claimData: ClaimData[] }> = ({ claimData }) => { id="search" value={val} onChange={(e) => setVal(e.target.value)} - className={"rounded-none rounded-l-md"} + className={"rounded-none rounded-l-md text-black"} placeholder={"challenge string"} />
-

+
{" "} + onClick={handleDefend} + >
diff --git a/src/components/Wallet/Provider.tsx b/src/components/Wallet/Provider.tsx index 210af60..881d71d 100644 --- a/src/components/Wallet/Provider.tsx +++ b/src/components/Wallet/Provider.tsx @@ -1,35 +1,22 @@ - +"use client" import '@rainbow-me/rainbowkit/styles.css'; import { getDefaultConfig, RainbowKitProvider, } from '@rainbow-me/rainbowkit'; import { WagmiProvider } from 'wagmi'; -import { - mainnet, - sepolia -} from 'wagmi/chains'; import { QueryClientProvider, QueryClient, } from "@tanstack/react-query"; import { ReactNode, useMemo } from 'react'; -import { useNetworkConfig } from '@/hooks/useNetworkConfig'; +import useWagmiRainbowConfig from '@/hooks/useWagmiConfig'; const queryClient = new QueryClient(); const Provider = ({ children }: { children: ReactNode }) => { - const { network } = useNetworkConfig() - const isMainnet = useMemo(() => { - return network === 'mainnet' - }, [network]) - const config = getDefaultConfig({ - appName: 'SuperProof explorer', - projectId: '876a28d2d23153fe7f76c24bacbabb72', - chains: [isMainnet ? mainnet : sepolia], - ssr: true - }); + const config = useWagmiRainbowConfig() return ( diff --git a/src/hooks/useCaculateClaim.ts b/src/hooks/useCaculateClaim.ts index e5a07be..08369e6 100644 --- a/src/hooks/useCaculateClaim.ts +++ b/src/hooks/useCaculateClaim.ts @@ -1,16 +1,14 @@ +import { post } from '@/service'; import useSWRMutation, { SWRMutationResponse } from 'swr/mutation' type CalculateArgs = { disputeGame: string - position: string + position: number } export const useCalculateClaim = () => { const url = `/api/disputegames/calculate/claim`; async function fetcher(url: string, { arg }: { arg: CalculateArgs }) { - return await fetch(url, { - method: 'POST', - body: JSON.stringify(arg) - }) + return await post(url, arg) } const res = useSWRMutation(url, fetcher); return res diff --git a/src/hooks/useNetworkConfig.ts b/src/hooks/useNetworkConfig.ts index d223304..bcf5d54 100644 --- a/src/hooks/useNetworkConfig.ts +++ b/src/hooks/useNetworkConfig.ts @@ -2,7 +2,7 @@ import { NetworkConfig, networkConfigs, Network } from "@/utils/env"; import { useMemo } from "react"; export const useNetworkConfig = (): NetworkConfig => { - const host = window.location.host; + const host = window?.location?.host; const defaultNetwork = networkConfigs["sepolia"]; defaultNetwork.network = "sepolia"; const config = useMemo(() => { diff --git a/src/hooks/useWagmiConfig.ts b/src/hooks/useWagmiConfig.ts new file mode 100644 index 0000000..1957f45 --- /dev/null +++ b/src/hooks/useWagmiConfig.ts @@ -0,0 +1,42 @@ +import { useMemo } from "react"; +import { useNetworkConfig } from "./useNetworkConfig"; +import { getDefaultConfig } from "@rainbow-me/rainbowkit"; +import { mainnet, sepolia } from "viem/chains"; +import { http, createConfig } from 'wagmi' + +const useWagmiRainbowConfig = () => { + const { network } = useNetworkConfig() + + const isMainnet = useMemo(() => { + return network === 'mainnet' + }, [network]) + const config = getDefaultConfig({ + appName: 'SuperProof explorer', + projectId: '876a28d2d23153fe7f76c24bacbabb72', + chains: [isMainnet ? mainnet : sepolia], + ssr: true + }); + return config +} + +export default useWagmiRainbowConfig; + + +const useWagmiConfig = () => { + const { network } = useNetworkConfig() + const isMainnet = useMemo(() => { + return network === 'mainnet' + }, [network]) + const config = useMemo(() => createConfig({ + chains: [isMainnet ? mainnet : sepolia], + transports: { + [mainnet.id]: http(), + [sepolia.id]: http(), + }, + }), [isMainnet]) + return config +} + +export { + useWagmiConfig +} \ No newline at end of file diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 1d86c51..d0469a3 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -8,6 +8,7 @@ import { SkeletonTheme } from "react-loading-skeleton"; import AppLayout from "@/components/AppLayout/AppLayout"; import { useIsMounted } from "@/hooks/useIsMounted"; import Script from "next/script"; +import WalletProvider from "@/components/Wallet/Provider"; const App = ({ Component, pageProps }: NextAppProps) => { const { resolvedTheme } = useTheme(); @@ -41,7 +42,9 @@ const App = ({ Component, pageProps }: NextAppProps) => { `} - + + + {/* {env.NEXT_PUBLIC_VERCEL_ANALYTICS_ENABLED && } */} diff --git a/src/pages/game/[game].tsx b/src/pages/game/[game].tsx index d986279..9e3d681 100644 --- a/src/pages/game/[game].tsx +++ b/src/pages/game/[game].tsx @@ -15,13 +15,10 @@ import { Card } from "@/components/Cards/Card"; import ClaimCard from "@/components/Cards/SurfaceCards/ClaimCard"; import { SlidableList } from "@/components/SlidableList"; import { useNetworkConfig } from "@/hooks/useNetworkConfig"; -import Challenge from "@/components/Challenge"; -import Provider from "@/components/Wallet/Provider"; const GameDetail = () => { const router = useRouter(); const address = (router.query.game as string | undefined) ?? ""; - const { data, isLoading } = useClaimData(address); const { data: game, isLoading: gameLoading } = useLatestGame({ hitsPerPage: 1, @@ -92,9 +89,7 @@ const GameDetail = () => { ) : ( - - - + )}