diff --git a/packages/nextjs/components/blockexplorer/TransactionsTable.tsx b/packages/nextjs/components/blockexplorer/TransactionsTable.tsx index d447aaea6..5f9d4611c 100644 --- a/packages/nextjs/components/blockexplorer/TransactionsTable.tsx +++ b/packages/nextjs/components/blockexplorer/TransactionsTable.tsx @@ -4,7 +4,7 @@ import { Address } from "~~/components/scaffold-eth"; import { TransactionWithFunction, getTargetNetwork } from "~~/utils/scaffold-eth"; import { TransactionsTableProps } from "~~/utils/scaffold-eth/"; -export const TransactionsTable = ({ blocks, transactionReceipts, isLoading }: TransactionsTableProps) => { +export const TransactionsTable = ({ blocks, transactionReceipts }: TransactionsTableProps) => { const targetNetwork = getTargetNetwork(); return ( @@ -22,64 +22,47 @@ export const TransactionsTable = ({ blocks, transactionReceipts, isLoading }: Tr Value ({targetNetwork.nativeCurrency.symbol}) - {isLoading ? ( - - {[...Array(20)].map((_, rowIndex) => ( - - {[...Array(7)].map((_, colIndex) => ( - -
- - ))} - - ))} - - ) : ( - - {blocks.map(block => - (block.transactions as TransactionWithFunction[]).map(tx => { - const receipt = transactionReceipts[tx.hash]; - const timeMined = new Date(Number(block.timestamp) * 1000).toLocaleString(); - const functionCalled = tx.input.substring(0, 10); + + {blocks.map(block => + (block.transactions as TransactionWithFunction[]).map(tx => { + const receipt = transactionReceipts[tx.hash]; + const timeMined = new Date(Number(block.timestamp) * 1000).toLocaleString(); + const functionCalled = tx.input.substring(0, 10); - return ( - - - - - - {tx.functionName === "0x" ? "" : {tx.functionName}} - {functionCalled !== "0x" && ( - {functionCalled} - )} - - {block.number?.toString()} - {timeMined} - -
- - - {!receipt?.contractAddress ? ( - tx.to &&
- ) : ( -
-
- (Contract Creation) -
- )} - - - {formatEther(tx.value)} {targetNetwork.nativeCurrency.symbol} - - - ); - }), - )} - - )} + return ( + + + + + + {tx.functionName === "0x" ? "" : {tx.functionName}} + {functionCalled !== "0x" && ( + {functionCalled} + )} + + {block.number?.toString()} + {timeMined} + +
+ + + {!receipt?.contractAddress ? ( + tx.to &&
+ ) : ( +
+
+ (Contract Creation) +
+ )} + + + {formatEther(tx.value)} {targetNetwork.nativeCurrency.symbol} + + + ); + }), + )} + diff --git a/packages/nextjs/hooks/scaffold-eth/useFetchBlocks.ts b/packages/nextjs/hooks/scaffold-eth/useFetchBlocks.ts index c927d6a32..0918c65e3 100644 --- a/packages/nextjs/hooks/scaffold-eth/useFetchBlocks.ts +++ b/packages/nextjs/hooks/scaffold-eth/useFetchBlocks.ts @@ -1,29 +1,41 @@ import { useCallback, useEffect, useState } from "react"; -import { Block, Transaction, TransactionReceipt } from "viem"; -import { usePublicClient } from "wagmi"; +import { + Block, + Hash, + Transaction, + TransactionReceipt, + createTestClient, + publicActions, + walletActions, + webSocket, +} from "viem"; import { hardhat } from "wagmi/chains"; import { decodeTransactionData } from "~~/utils/scaffold-eth"; const BLOCKS_PER_PAGE = 20; -export const useFetchBlocks = () => { - const client = usePublicClient({ chainId: hardhat.id }); +export const testClient = createTestClient({ + chain: hardhat, + mode: "hardhat", + transport: webSocket("ws://127.0.0.1:8545"), +}) + .extend(publicActions) + .extend(walletActions); +export const useFetchBlocks = () => { const [blocks, setBlocks] = useState([]); const [transactionReceipts, setTransactionReceipts] = useState<{ [key: string]: TransactionReceipt; }>({}); const [currentPage, setCurrentPage] = useState(0); const [totalBlocks, setTotalBlocks] = useState(0n); - const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const fetchBlocks = useCallback(async () => { - setIsLoading(true); setError(null); try { - const blockNumber = await client.getBlockNumber(); + const blockNumber = await testClient.getBlockNumber(); setTotalBlocks(blockNumber); const startingBlock = blockNumber - BigInt(currentPage * BLOCKS_PER_PAGE); @@ -34,7 +46,7 @@ export const useFetchBlocks = () => { const blocksWithTransactions = blockNumbersToFetch.map(async blockNumber => { try { - return client.getBlock({ blockNumber, includeTransactions: true }); + return testClient.getBlock({ blockNumber, includeTransactions: true }); } catch (err) { setError(err instanceof Error ? err : new Error("An error occurred.")); throw err; @@ -50,7 +62,7 @@ export const useFetchBlocks = () => { fetchedBlocks.flatMap(block => block.transactions.map(async tx => { try { - const receipt = await client.getTransactionReceipt({ hash: (tx as Transaction).hash }); + const receipt = await testClient.getTransactionReceipt({ hash: (tx as Transaction).hash }); return { [(tx as Transaction).hash]: receipt }; } catch (err) { setError(err instanceof Error ? err : new Error("An error occurred.")); @@ -65,47 +77,50 @@ export const useFetchBlocks = () => { } catch (err) { setError(err instanceof Error ? err : new Error("An error occurred.")); } - setIsLoading(false); - }, [client, currentPage]); + }, [currentPage]); useEffect(() => { fetchBlocks(); }, [fetchBlocks]); useEffect(() => { - const handleNewBlock = async (newBlock: Block) => { + const handleNewBlock = async (newBlock: any) => { try { - if (!blocks.some(block => block.number === newBlock.number)) { - if (currentPage === 0) { - setBlocks(prevBlocks => [newBlock, ...prevBlocks.slice(0, BLOCKS_PER_PAGE - 1)]); - - newBlock.transactions.forEach(tx => decodeTransactionData(tx as Transaction)); - - const receipts = await Promise.all( - newBlock.transactions.map(async tx => { - try { - const receipt = await client.getTransactionReceipt({ hash: (tx as Transaction).hash }); - return { [(tx as Transaction).hash]: receipt }; - } catch (err) { - setError(err instanceof Error ? err : new Error("An error occurred.")); - throw err; - } - }), + if (currentPage === 0) { + if (newBlock.transactions.length > 0) { + const transactionsDetails = await Promise.all( + newBlock.transactions.map((txHash: string) => testClient.getTransaction({ hash: txHash as Hash })), ); - - setTransactionReceipts(prevReceipts => ({ ...prevReceipts, ...Object.assign({}, ...receipts) })); - } - if (newBlock.number) { - setTotalBlocks(newBlock.number); + newBlock.transactions = transactionsDetails; } + + newBlock.transactions.forEach((tx: Transaction) => decodeTransactionData(tx as Transaction)); + + const receipts = await Promise.all( + newBlock.transactions.map(async (tx: Transaction) => { + try { + const receipt = await testClient.getTransactionReceipt({ hash: (tx as Transaction).hash }); + return { [(tx as Transaction).hash]: receipt }; + } catch (err) { + setError(err instanceof Error ? err : new Error("An error occurred fetching receipt.")); + throw err; + } + }), + ); + + setBlocks(prevBlocks => [newBlock, ...prevBlocks.slice(0, BLOCKS_PER_PAGE - 1)]); + setTransactionReceipts(prevReceipts => ({ ...prevReceipts, ...Object.assign({}, ...receipts) })); + } + if (newBlock.number) { + setTotalBlocks(newBlock.number); } } catch (err) { setError(err instanceof Error ? err : new Error("An error occurred.")); } }; - return client.watchBlocks({ onBlock: handleNewBlock, includeTransactions: true }); - }, [blocks, client, currentPage]); + return testClient.watchBlocks({ onBlock: handleNewBlock, includeTransactions: true }); + }, [currentPage]); return { blocks, @@ -113,7 +128,6 @@ export const useFetchBlocks = () => { currentPage, totalBlocks, setCurrentPage, - isLoading, error, }; }; diff --git a/packages/nextjs/pages/blockexplorer/address/[address].tsx b/packages/nextjs/pages/blockexplorer/address/[address].tsx index 6f975df55..6e936fe21 100644 --- a/packages/nextjs/pages/blockexplorer/address/[address].tsx +++ b/packages/nextjs/pages/blockexplorer/address/[address].tsx @@ -34,7 +34,7 @@ const publicClient = createPublicClient({ const AddressPage = ({ address, contractData }: PageProps) => { const router = useRouter(); - const { blocks, transactionReceipts, currentPage, totalBlocks, setCurrentPage, isLoading } = useFetchBlocks(); + const { blocks, transactionReceipts, currentPage, totalBlocks, setCurrentPage } = useFetchBlocks(); const [activeTab, setActiveTab] = useState("transactions"); const [isContract, setIsContract] = useState(false); @@ -108,7 +108,7 @@ const AddressPage = ({ address, contractData }: PageProps) => { )} {activeTab === "transactions" && (
- + { - const { blocks, transactionReceipts, currentPage, totalBlocks, setCurrentPage, isLoading, error } = useFetchBlocks(); + const { blocks, transactionReceipts, currentPage, totalBlocks, setCurrentPage, error } = useFetchBlocks(); useEffect(() => { if (getTargetNetwork().id === hardhat.id && error) { @@ -51,7 +51,7 @@ const Blockexplorer: NextPage = () => { return (
- +
); diff --git a/packages/nextjs/utils/scaffold-eth/block.ts b/packages/nextjs/utils/scaffold-eth/block.ts index ae22f3152..4cd753fe3 100644 --- a/packages/nextjs/utils/scaffold-eth/block.ts +++ b/packages/nextjs/utils/scaffold-eth/block.ts @@ -14,5 +14,4 @@ interface TransactionReceipts { export interface TransactionsTableProps { blocks: Block[]; transactionReceipts: TransactionReceipts; - isLoading: boolean; } diff --git a/packages/nextjs/utils/scaffold-eth/decodeTxData.ts b/packages/nextjs/utils/scaffold-eth/decodeTxData.ts index a32ceabf5..423fe50f3 100644 --- a/packages/nextjs/utils/scaffold-eth/decodeTxData.ts +++ b/packages/nextjs/utils/scaffold-eth/decodeTxData.ts @@ -17,7 +17,7 @@ const interfaces = chainMetaData : {}; export const decodeTransactionData = (tx: TransactionWithFunction) => { - if (tx.input.length >= 10) { + if (tx.input.length >= 10 && !tx.input.startsWith("0x60e06040")) { for (const [, contractAbi] of Object.entries(interfaces)) { try { const { functionName, args } = decodeFunctionData({