diff --git a/packages/nextjs/app/blockexplorer/_components/SearchBar.tsx b/packages/nextjs/app/blockexplorer/_components/SearchBar.tsx index 82b883987..e602096d3 100644 --- a/packages/nextjs/app/blockexplorer/_components/SearchBar.tsx +++ b/packages/nextjs/app/blockexplorer/_components/SearchBar.tsx @@ -16,7 +16,7 @@ export const SearchBar = () => { event.preventDefault(); if (isHex(searchInput)) { try { - const tx = await client.getTransaction({ hash: searchInput }); + const tx = await client?.getTransaction({ hash: searchInput }); if (tx) { router.push(`/blockexplorer/transaction/${searchInput}`); return; diff --git a/packages/nextjs/app/blockexplorer/transaction/[txHash]/page.tsx b/packages/nextjs/app/blockexplorer/transaction/[txHash]/page.tsx index d9c45f557..f3e0431df 100644 --- a/packages/nextjs/app/blockexplorer/transaction/[txHash]/page.tsx +++ b/packages/nextjs/app/blockexplorer/transaction/[txHash]/page.tsx @@ -25,7 +25,7 @@ const TransactionPage: NextPage = ({ params }: PageProps) => { const { targetNetwork } = useTargetNetwork(); useEffect(() => { - if (txHash) { + if (txHash && client) { const fetchTransaction = async () => { const tx = await client.getTransaction({ hash: txHash }); const receipt = await client.getTransactionReceipt({ hash: txHash }); diff --git a/packages/nextjs/app/debug/_components/contract/DisplayVariable.tsx b/packages/nextjs/app/debug/_components/contract/DisplayVariable.tsx index 805593d05..bf7fe3f45 100644 --- a/packages/nextjs/app/debug/_components/contract/DisplayVariable.tsx +++ b/packages/nextjs/app/debug/_components/contract/DisplayVariable.tsx @@ -5,10 +5,11 @@ import { InheritanceTooltip } from "./InheritanceTooltip"; import { displayTxResult } from "./utilsDisplay"; import { Abi, AbiFunction } from "abitype"; import { Address } from "viem"; -import { useContractRead } from "wagmi"; +import { useReadContract } from "wagmi"; import { ArrowPathIcon } from "@heroicons/react/24/outline"; import { useAnimationConfig } from "~~/hooks/scaffold-eth"; -import { notification } from "~~/utils/scaffold-eth"; +import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork"; +import { getParsedError, notification } from "~~/utils/scaffold-eth"; type DisplayVariableProps = { contractAddress: Address; @@ -25,16 +26,20 @@ export const DisplayVariable = ({ abi, inheritedFrom, }: DisplayVariableProps) => { + const { targetNetwork } = useTargetNetwork(); + const { data: result, isFetching, refetch, - } = useContractRead({ + error, + } = useReadContract({ address: contractAddress, functionName: abiFunction.name, abi: abi, - onError: error => { - notification.error(error.message); + chainId: targetNetwork.id, + query: { + retry: false, }, }); @@ -44,6 +49,13 @@ export const DisplayVariable = ({ refetch(); }, [refetch, refreshDisplayVariables]); + useEffect(() => { + if (error) { + const parsedError = getParsedError(error); + notification.error(parsedError); + } + }, [error]); + return (
diff --git a/packages/nextjs/app/debug/_components/contract/ReadOnlyFunctionForm.tsx b/packages/nextjs/app/debug/_components/contract/ReadOnlyFunctionForm.tsx index 91bae120b..9ccc37fed 100644 --- a/packages/nextjs/app/debug/_components/contract/ReadOnlyFunctionForm.tsx +++ b/packages/nextjs/app/debug/_components/contract/ReadOnlyFunctionForm.tsx @@ -1,10 +1,10 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { InheritanceTooltip } from "./InheritanceTooltip"; import { Abi, AbiFunction } from "abitype"; import { Address } from "viem"; -import { useContractRead } from "wagmi"; +import { useReadContract } from "wagmi"; import { ContractInput, displayTxResult, @@ -13,6 +13,7 @@ import { getParsedContractFunctionArgs, transformAbiFunction, } from "~~/app/debug/_components/contract"; +import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork"; import { getParsedError, notification } from "~~/utils/scaffold-eth"; type ReadOnlyFunctionFormProps = { @@ -30,19 +31,27 @@ export const ReadOnlyFunctionForm = ({ }: ReadOnlyFunctionFormProps) => { const [form, setForm] = useState>(() => getInitialFormState(abiFunction)); const [result, setResult] = useState(); + const { targetNetwork } = useTargetNetwork(); - const { isFetching, refetch } = useContractRead({ + const { isFetching, refetch, error } = useReadContract({ address: contractAddress, functionName: abiFunction.name, abi: abi, args: getParsedContractFunctionArgs(form), - enabled: false, - onError: (error: any) => { - const parsedErrror = getParsedError(error); - notification.error(parsedErrror); + chainId: targetNetwork.id, + query: { + enabled: false, + retry: false, }, }); + useEffect(() => { + if (error) { + const parsedError = getParsedError(error); + notification.error(parsedError); + } + }, [error]); + const transformedFunction = transformAbiFunction(abiFunction); const inputElements = transformedFunction.inputs.map((input, inputIndex) => { const key = getFunctionInputKey(abiFunction.name, input, inputIndex); diff --git a/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx b/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx index 7d7574645..b8e8f8490 100644 --- a/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx +++ b/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx @@ -4,7 +4,7 @@ import { useEffect, useState } from "react"; import { InheritanceTooltip } from "./InheritanceTooltip"; import { Abi, AbiFunction } from "abitype"; import { Address, TransactionReceipt } from "viem"; -import { useContractWrite, useNetwork, useWaitForTransaction } from "wagmi"; +import { useAccount, useWaitForTransactionReceipt, useWriteContract } from "wagmi"; import { ContractInput, TxReceipt, @@ -34,26 +34,24 @@ export const WriteOnlyFunctionForm = ({ }: WriteOnlyFunctionFormProps) => { const [form, setForm] = useState>(() => getInitialFormState(abiFunction)); const [txValue, setTxValue] = useState(""); - const { chain } = useNetwork(); + const { chain } = useAccount(); const writeTxn = useTransactor(); const { targetNetwork } = useTargetNetwork(); const writeDisabled = !chain || chain?.id !== targetNetwork.id; - const { - data: result, - isLoading, - writeAsync, - } = useContractWrite({ - address: contractAddress, - functionName: abiFunction.name, - abi: abi, - args: getParsedContractFunctionArgs(form), - }); + const { data: result, isPending, writeContractAsync } = useWriteContract(); const handleWrite = async () => { - if (writeAsync) { + if (writeContractAsync) { try { - const makeWriteWithParams = () => writeAsync({ value: BigInt(txValue) }); + const makeWriteWithParams = () => + writeContractAsync({ + address: contractAddress, + functionName: abiFunction.name, + abi: abi, + args: getParsedContractFunctionArgs(form), + value: BigInt(txValue), + }); await writeTxn(makeWriteWithParams); onChange(); } catch (e: any) { @@ -63,8 +61,8 @@ export const WriteOnlyFunctionForm = ({ }; const [displayedTxResult, setDisplayedTxResult] = useState(); - const { data: txResult } = useWaitForTransaction({ - hash: result?.hash, + const { data: txResult } = useWaitForTransactionReceipt({ + hash: result, }); useEffect(() => { setDisplayedTxResult(txResult); @@ -126,8 +124,8 @@ export const WriteOnlyFunctionForm = ({ }`} data-tip={`${writeDisabled && "Wallet not connected or in the wrong network"}`} > -
diff --git a/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx b/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx index 56a82f6de..05273c2b7 100644 --- a/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx +++ b/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx @@ -2,9 +2,10 @@ import { useEffect, useState } from "react"; import { RainbowKitProvider, darkTheme, lightTheme } from "@rainbow-me/rainbowkit"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { useTheme } from "next-themes"; import { Toaster } from "react-hot-toast"; -import { WagmiConfig } from "wagmi"; +import { WagmiProvider } from "wagmi"; import { Footer } from "~~/components/Footer"; import { Header } from "~~/components/Header"; import { BlockieAvatar } from "~~/components/scaffold-eth"; @@ -12,7 +13,6 @@ import { ProgressBar } from "~~/components/scaffold-eth/ProgressBar"; import { useNativeCurrencyPrice } from "~~/hooks/scaffold-eth"; import { useGlobalState } from "~~/services/store/store"; import { wagmiConfig } from "~~/services/web3/wagmiConfig"; -import { appChains } from "~~/services/web3/wagmiConnectors"; const ScaffoldEthApp = ({ children }: { children: React.ReactNode }) => { const price = useNativeCurrencyPrice(); @@ -36,6 +36,14 @@ const ScaffoldEthApp = ({ children }: { children: React.ReactNode }) => { ); }; +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + }, + }, +}); + export const ScaffoldEthAppWithProviders = ({ children }: { children: React.ReactNode }) => { const { resolvedTheme } = useTheme(); const isDarkMode = resolvedTheme === "dark"; @@ -46,15 +54,16 @@ export const ScaffoldEthAppWithProviders = ({ children }: { children: React.Reac }, []); return ( - - - - {children} - - + + + + + {children} + + + ); }; diff --git a/packages/nextjs/components/scaffold-eth/Address.tsx b/packages/nextjs/components/scaffold-eth/Address.tsx index 1c1ad600a..2241edc89 100644 --- a/packages/nextjs/components/scaffold-eth/Address.tsx +++ b/packages/nextjs/components/scaffold-eth/Address.tsx @@ -5,6 +5,7 @@ import Link from "next/link"; import { CopyToClipboard } from "react-copy-to-clipboard"; import { Address as AddressType, getAddress, isAddress } from "viem"; import { hardhat } from "viem/chains"; +import { normalize } from "viem/ens"; import { useEnsAvatar, useEnsName } from "wagmi"; import { CheckCircleIcon, DocumentDuplicateIcon } from "@heroicons/react/24/outline"; import { BlockieAvatar } from "~~/components/scaffold-eth"; @@ -41,14 +42,18 @@ export const Address = ({ address, disableAddressLink, format, size = "base" }: const { data: fetchedEns } = useEnsName({ address: checkSumAddress, - enabled: isAddress(checkSumAddress ?? ""), chainId: 1, + query: { + enabled: isAddress(checkSumAddress ?? ""), + }, }); const { data: fetchedEnsAvatar } = useEnsAvatar({ - name: fetchedEns, - enabled: Boolean(fetchedEns), + name: fetchedEns ? normalize(fetchedEns) : undefined, chainId: 1, - cacheTime: 30_000, + query: { + enabled: Boolean(fetchedEns), + gcTime: 30_000, + }, }); // We need to apply this pattern to avoid Hydration errors. diff --git a/packages/nextjs/components/scaffold-eth/Balance.tsx b/packages/nextjs/components/scaffold-eth/Balance.tsx index d778cb44f..0108e953a 100644 --- a/packages/nextjs/components/scaffold-eth/Balance.tsx +++ b/packages/nextjs/components/scaffold-eth/Balance.tsx @@ -1,8 +1,9 @@ "use client"; -import { useState } from "react"; -import { Address } from "viem"; -import { useBalance } from "wagmi"; +import { useEffect, useState } from "react"; +import { useQueryClient } from "@tanstack/react-query"; +import { Address, formatEther } from "viem"; +import { useBalance, useBlockNumber } from "wagmi"; import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork"; import { useGlobalState } from "~~/services/store/store"; @@ -18,14 +19,16 @@ type BalanceProps = { export const Balance = ({ address, className = "", usdMode }: BalanceProps) => { const { targetNetwork } = useTargetNetwork(); + const queryClient = useQueryClient(); + const { data: blockNumber } = useBlockNumber({ watch: true, chainId: targetNetwork.id }); const price = useGlobalState(state => state.nativeCurrencyPrice); const { data: balance, isError, isLoading, + queryKey, } = useBalance({ address, - watch: true, }); const [displayUsdMode, setDisplayUsdMode] = useState(price > 0 ? Boolean(usdMode) : false); @@ -36,6 +39,11 @@ export const Balance = ({ address, className = "", usdMode }: BalanceProps) => { } }; + useEffect(() => { + queryClient.invalidateQueries({ queryKey }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [blockNumber]); + if (!address || isLoading || balance === null) { return (
@@ -55,7 +63,7 @@ export const Balance = ({ address, className = "", usdMode }: BalanceProps) => { ); } - const formattedBalance = balance ? Number(balance.formatted) : 0; + const formattedBalance = balance ? Number(formatEther(balance.value)) : 0; return (