diff --git a/README.md b/README.md index afa6c4b..d6d5eb5 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,9 @@ ⚙️ Built using NextJS, RainbowKit and Typescript. - ✅ **Contract Hot Reload**: Your frontend auto-adapts to your smart contract as you edit it. -- 🪝 **[Custom hooks](https://docs.scaffoldeth.io/hooks/)**: Collection of React hooks wrapper around [wagmi](https://wagmi.sh/) to simplify interactions with smart contracts with typescript autocompletion. +- 🪝 **[Custom hooks](https://docs.scaffoldeth.io/hooks/)**: Collection of React hooks to simplify interactions with smart contracts. - 🧱 [**Components**](https://docs.scaffoldeth.io/components/): Collection of common web3 components to quickly build your frontend. -- 🔥 **Burner Wallet & Local Faucet**: Quickly test your application with a burner wallet and local faucet. -- 🔐 **Integration with Wallet Providers**: Connect to different wallet providers and interact with the Ethereum network. +- 🔐 **Integration with Wallet Providers**: Connect your Petra Wallet and interact with the Aptos or Movement M1 network. ![Debug Contracts tab](https://github.com/scaffold-eth/scaffold-eth-2/assets/55535804/b237af0c-5027-4849-a5c1-2e31495cccb1) @@ -32,8 +31,8 @@ To get started with Scaffold-Move, follow the steps below: 1. Clone this repo & install dependencies ``` -git clone https://github.com/scaffold-eth/scaffold-eth-2.git -cd scaffold-eth-2 +git clone https://github.com/arjanjohan/scaffold-move.git +cd scaffold-move yarn install ``` @@ -43,15 +42,26 @@ yarn install yarn chain ``` -This command starts a local Ethereum network using Hardhat. The network runs on your local machine and can be used for testing and development. You can customize the network configuration in `hardhat.config.ts`. +This command starts a local Ethereum network using Hardhat. The network runs on your local machine and can be used for testing and development. You can customize the network configuration in `hardhat.config.ts`. +// TODO: rewrite this for Movement -3. On a second terminal, deploy the test contract: +3. On a second terminal, initialize a new account. + +TODO: create yarn script for this. + +``` +movement aptos init +``` + +Choose custom and enter `https://devnet.m1.movementlabs.xyz/` as rest and faucet endpoints. + +3a. Deploy the test contract: ``` yarn deploy ``` -This command deploys a test smart contract to the local network. The contract is located in `packages/hardhat/contracts` and can be modified to suit your needs. The `yarn deploy` command uses the deploy script located in `packages/hardhat/deploy` to deploy the contract to the network. You can also customize the deploy script. +This command deploys a test smart contract to the local network. The contract is located in `packages/hardhat/contracts` and can be modified to suit your needs. The `yarn deploy` command uses `movement aptos move publish` to publish the contract to the network. After this is executes the script located in `scripts/loadContracts.js` to make the new contracts available in the nextjs frontend. 4. On a third terminal, start your NextJS app: @@ -67,16 +77,19 @@ Visit your app on: `http://localhost:3000`. You can interact with your smart con - Edit your frontend homepage at `packages/nextjs/app/page.tsx`. For guidance on [routing](https://nextjs.org/docs/app/building-your-application/routing/defining-routes) and configuring [pages/layouts](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts) checkout the Next.js documentation. -## TODO: +## Next steps + +For this hackathon I kept the scope small due to the time constraints. I build only the most essential and useful features, so that developers can start using Scaffold Move right away. However, there is much more that I want to add to this project after the hackathon. If you have any ideas or suggestions, please reach out and I will add it to this list. - Styling wallet connect button - Store network data in scaffold-config - Debug page - - Display Resources? - - Read and write functionality -- Make Move hooks for ScaffoldReadContract and ScaffoldWriteContract + - Display Resources as well? + - Msg for no result on view methods - Add `aptos init` script that runs `aptos init` and then copies the new address to the `move.toml` file. -- Hot contract reload: Add `aptos move deploy` script that copies the address to the frontend file `addresses.ts`. +- Fix colors for dark mode +- Ensure export default deployedContracts satisfies GenericContractsDeclaration +- Add block explorer page ## Links diff --git a/packages/nextjs/app/blockexplorer/_components/AddressCodeTab.tsx b/packages/nextjs/app/blockexplorer/_components/AddressCodeTab.tsx deleted file mode 100644 index ee74741..0000000 --- a/packages/nextjs/app/blockexplorer/_components/AddressCodeTab.tsx +++ /dev/null @@ -1,27 +0,0 @@ -type AddressCodeTabProps = { - bytecode: string; - assembly: string; -}; - -export const AddressCodeTab = ({ bytecode, assembly }: AddressCodeTabProps) => { - const formattedAssembly = Array.from(assembly.matchAll(/\w+( 0x[a-fA-F0-9]+)?/g)) - .map(it => it[0]) - .join("\n"); - - return ( -
- Bytecode -
-
-          {bytecode}
-        
-
- Opcodes -
-
-          {formattedAssembly}
-        
-
-
- ); -}; diff --git a/packages/nextjs/app/blockexplorer/_components/AddressComponent.tsx b/packages/nextjs/app/blockexplorer/_components/AddressComponent.tsx deleted file mode 100644 index c0c14d6..0000000 --- a/packages/nextjs/app/blockexplorer/_components/AddressComponent.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { BackButton } from "./BackButton"; -import { ContractTabs } from "./ContractTabs"; -import { Address, Balance } from "~~/components/scaffold-eth"; - -export const AddressComponent = ({ - address, - contractData, -}: { - address: string; - contractData: { bytecode: string; assembly: string } | null; -}) => { - return ( -
-
- -
-
-
-
-
-
-
-
- Balance: - -
-
-
-
-
-
- -
- ); -}; diff --git a/packages/nextjs/app/blockexplorer/_components/AddressLogsTab.tsx b/packages/nextjs/app/blockexplorer/_components/AddressLogsTab.tsx deleted file mode 100644 index 9d2ab0e..0000000 --- a/packages/nextjs/app/blockexplorer/_components/AddressLogsTab.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Address } from "viem"; -import { useContractLogs } from "~~/hooks/scaffold-eth"; -import { replacer } from "~~/utils/scaffold-eth/common"; - -export const AddressLogsTab = ({ address }: { address: Address }) => { - const contractLogs = useContractLogs(address); - - return ( -
-
-
-          {contractLogs.map((log, i) => (
-            
- Log: {JSON.stringify(log, replacer, 2)} -
- ))} -
-
-
- ); -}; diff --git a/packages/nextjs/app/blockexplorer/_components/AddressStorageTab.tsx b/packages/nextjs/app/blockexplorer/_components/AddressStorageTab.tsx deleted file mode 100644 index 86c4f21..0000000 --- a/packages/nextjs/app/blockexplorer/_components/AddressStorageTab.tsx +++ /dev/null @@ -1,61 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { Address, createPublicClient, http, toHex } from "viem"; -import { hardhat } from "viem/chains"; - -const publicClient = createPublicClient({ - chain: hardhat, - transport: http(), -}); - -export const AddressStorageTab = ({ address }: { address: Address }) => { - const [storage, setStorage] = useState([]); - - useEffect(() => { - const fetchStorage = async () => { - try { - const storageData = []; - let idx = 0; - - while (true) { - const storageAtPosition = await publicClient.getStorageAt({ - address: address, - slot: toHex(idx), - }); - - if (storageAtPosition === "0x" + "0".repeat(64)) break; - - if (storageAtPosition) { - storageData.push(storageAtPosition); - } - - idx++; - } - setStorage(storageData); - } catch (error) { - console.error("Failed to fetch storage:", error); - } - }; - - fetchStorage(); - }, [address]); - - return ( -
- {storage.length > 0 ? ( -
-
-            {storage.map((data, i) => (
-              
- Storage Slot {i}: {data} -
- ))} -
-
- ) : ( -
This contract does not have any variables.
- )} -
- ); -}; diff --git a/packages/nextjs/app/blockexplorer/_components/BackButton.tsx b/packages/nextjs/app/blockexplorer/_components/BackButton.tsx deleted file mode 100644 index bdfde8b..0000000 --- a/packages/nextjs/app/blockexplorer/_components/BackButton.tsx +++ /dev/null @@ -1,12 +0,0 @@ -"use client"; - -import { useRouter } from "next/navigation"; - -export const BackButton = () => { - const router = useRouter(); - return ( - - ); -}; diff --git a/packages/nextjs/app/blockexplorer/_components/ContractTabs.tsx b/packages/nextjs/app/blockexplorer/_components/ContractTabs.tsx deleted file mode 100644 index bb020ef..0000000 --- a/packages/nextjs/app/blockexplorer/_components/ContractTabs.tsx +++ /dev/null @@ -1,92 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { AddressCodeTab } from "./AddressCodeTab"; -import { AddressLogsTab } from "./AddressLogsTab"; -import { AddressStorageTab } from "./AddressStorageTab"; -import { PaginationButton } from "./PaginationButton"; -import { TransactionsTable } from "./TransactionsTable"; -import { createPublicClient, http } from "viem"; -import { hardhat } from "viem/chains"; -import { useFetchBlocks } from "~~/hooks/scaffold-eth"; - -type AddressCodeTabProps = { - bytecode: string; - assembly: string; -}; - -type PageProps = { - address: string; - contractData: AddressCodeTabProps | null; -}; - -const publicClient = createPublicClient({ - chain: hardhat, - transport: http(), -}); - -export const ContractTabs = ({ address, contractData }: PageProps) => { - const { blocks, transactionReceipts, currentPage, totalBlocks, setCurrentPage } = useFetchBlocks(); - const [activeTab, setActiveTab] = useState("transactions"); - const [isContract, setIsContract] = useState(false); - - useEffect(() => { - const checkIsContract = async () => { - const contractCode = await publicClient.getBytecode({ address: address }); - setIsContract(contractCode !== undefined && contractCode !== "0x"); - }; - - checkIsContract(); - }, [address]); - - const filteredBlocks = blocks.filter(block => - block.transactions.some(tx => { - if (typeof tx === "string") { - return false; - } - return tx.from.toLowerCase() === address.toLowerCase() || tx.to?.toLowerCase() === address.toLowerCase(); - }), - ); - - return ( - <> - {isContract && ( -
- - - - -
- )} - {activeTab === "transactions" && ( -
- - -
- )} - {activeTab === "code" && contractData && ( - - )} - {activeTab === "storage" && } - {activeTab === "logs" && } - - ); -}; diff --git a/packages/nextjs/app/blockexplorer/_components/PaginationButton.tsx b/packages/nextjs/app/blockexplorer/_components/PaginationButton.tsx deleted file mode 100644 index 77aefbc..0000000 --- a/packages/nextjs/app/blockexplorer/_components/PaginationButton.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/24/outline"; - -type PaginationButtonProps = { - currentPage: number; - totalItems: number; - setCurrentPage: (page: number) => void; -}; - -const ITEMS_PER_PAGE = 20; - -export const PaginationButton = ({ currentPage, totalItems, setCurrentPage }: PaginationButtonProps) => { - const isPrevButtonDisabled = currentPage === 0; - const isNextButtonDisabled = currentPage + 1 >= Math.ceil(totalItems / ITEMS_PER_PAGE); - - const prevButtonClass = isPrevButtonDisabled ? "bg-gray-200 cursor-default" : "btn btn-primary"; - const nextButtonClass = isNextButtonDisabled ? "bg-gray-200 cursor-default" : "btn btn-primary"; - - if (isNextButtonDisabled && isPrevButtonDisabled) return null; - - return ( -
- - Page {currentPage + 1} - -
- ); -}; diff --git a/packages/nextjs/app/blockexplorer/_components/SearchBar.tsx b/packages/nextjs/app/blockexplorer/_components/SearchBar.tsx deleted file mode 100644 index e602096..0000000 --- a/packages/nextjs/app/blockexplorer/_components/SearchBar.tsx +++ /dev/null @@ -1,49 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { useRouter } from "next/navigation"; -import { isAddress, isHex } from "viem"; -import { hardhat } from "viem/chains"; -import { usePublicClient } from "wagmi"; - -export const SearchBar = () => { - const [searchInput, setSearchInput] = useState(""); - const router = useRouter(); - - const client = usePublicClient({ chainId: hardhat.id }); - - const handleSearch = async (event: React.FormEvent) => { - event.preventDefault(); - if (isHex(searchInput)) { - try { - const tx = await client?.getTransaction({ hash: searchInput }); - if (tx) { - router.push(`/blockexplorer/transaction/${searchInput}`); - return; - } - } catch (error) { - console.error("Failed to fetch transaction:", error); - } - } - - if (isAddress(searchInput)) { - router.push(`/blockexplorer/address/${searchInput}`); - return; - } - }; - - return ( -
- setSearchInput(e.target.value)} - /> - -
- ); -}; diff --git a/packages/nextjs/app/blockexplorer/_components/TransactionHash.tsx b/packages/nextjs/app/blockexplorer/_components/TransactionHash.tsx deleted file mode 100644 index d4fd929..0000000 --- a/packages/nextjs/app/blockexplorer/_components/TransactionHash.tsx +++ /dev/null @@ -1,39 +0,0 @@ -"use client"; - -import { useState } from "react"; -import Link from "next/link"; -import { CopyToClipboard } from "react-copy-to-clipboard"; -import { CheckCircleIcon, DocumentDuplicateIcon } from "@heroicons/react/24/outline"; - -export const TransactionHash = ({ hash }: { hash: string }) => { - const [addressCopied, setAddressCopied] = useState(false); - - return ( -
- - {hash?.substring(0, 6)}...{hash?.substring(hash.length - 4)} - - {addressCopied ? ( -
- ); -}; diff --git a/packages/nextjs/app/blockexplorer/_components/TransactionsTable.tsx b/packages/nextjs/app/blockexplorer/_components/TransactionsTable.tsx deleted file mode 100644 index b91892c..0000000 --- a/packages/nextjs/app/blockexplorer/_components/TransactionsTable.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { TransactionHash } from "./TransactionHash"; -import { formatEther } from "viem"; -import { Address } from "~~/components/scaffold-eth"; -import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork"; -import { TransactionWithFunction } from "~~/utils/scaffold-eth"; -import { TransactionsTableProps } from "~~/utils/scaffold-eth/"; - -export const TransactionsTable = ({ blocks, transactionReceipts }: TransactionsTableProps) => { - const { targetNetwork } = useTargetNetwork(); - - return ( -
-
- - - - - - - - - - - - - - {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 ( - - - - - - - - - - ); - }), - )} - -
Transaction HashFunction CalledBlock NumberTime MinedFromToValue ({targetNetwork.nativeCurrency.symbol})
- - - {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/app/blockexplorer/_components/index.tsx b/packages/nextjs/app/blockexplorer/_components/index.tsx deleted file mode 100644 index 20d8eb2..0000000 --- a/packages/nextjs/app/blockexplorer/_components/index.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export * from "./SearchBar"; -export * from "./BackButton"; -export * from "./AddressCodeTab"; -export * from "./TransactionHash"; -export * from "./ContractTabs"; -export * from "./PaginationButton"; -export * from "./TransactionsTable"; diff --git a/packages/nextjs/app/blockexplorer/address/[address]/page.tsx b/packages/nextjs/app/blockexplorer/address/[address]/page.tsx deleted file mode 100644 index 7cc623b..0000000 --- a/packages/nextjs/app/blockexplorer/address/[address]/page.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import fs from "fs"; -import path from "path"; -import { hardhat } from "viem/chains"; -import { AddressComponent } from "~~/app/blockexplorer/_components/AddressComponent"; - -import deployedModules from "~~/contracts/deployedModules"; - -import { isZeroAddress } from "~~/utils/scaffold-eth/common"; -import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract"; - -type PageProps = { - params: { address: string }; -}; - -async function fetchByteCodeAndAssembly(buildInfoDirectory: string, contractPath: string) { - const buildInfoFiles = fs.readdirSync(buildInfoDirectory); - let bytecode = ""; - let assembly = ""; - - for (let i = 0; i < buildInfoFiles.length; i++) { - const filePath = path.join(buildInfoDirectory, buildInfoFiles[i]); - - const buildInfo = JSON.parse(fs.readFileSync(filePath, "utf8")); - - if (buildInfo.output.contracts[contractPath]) { - for (const contract in buildInfo.output.contracts[contractPath]) { - bytecode = buildInfo.output.contracts[contractPath][contract].evm.bytecode.object; - assembly = buildInfo.output.contracts[contractPath][contract].evm.bytecode.opcodes; - break; - } - } - - if (bytecode && assembly) { - break; - } - } - - return { bytecode, assembly }; -} - -const getContractData = async (address: string) => { - const contracts = deployedModules as GenericContractsDeclaration | null; - const chainId = hardhat.id; - let contractPath = ""; - - const buildInfoDirectory = path.join( - __dirname, - "..", - "..", - "..", - "..", - "..", - "..", - "..", - "hardhat", - "artifacts", - "build-info", - ); - - if (!fs.existsSync(buildInfoDirectory)) { - throw new Error(`Directory ${buildInfoDirectory} not found.`); - } - - const deployedContractsOnChain = contracts ? contracts[chainId] : {}; - for (const [contractName, contractInfo] of Object.entries(deployedContractsOnChain)) { - if (contractInfo.address.toLowerCase() === address.toLowerCase()) { - contractPath = `contracts/${contractName}.sol`; - break; - } - } - - if (!contractPath) { - // No contract found at this address - return null; - } - - const { bytecode, assembly } = await fetchByteCodeAndAssembly(buildInfoDirectory, contractPath); - - return { bytecode, assembly }; -}; - -export function generateStaticParams() { - // An workaround to enable static exports in Next.js, generating single dummy page. - return [{ address: "0x0000000000000000000000000000000000000000" }]; -} - -const AddressPage = async ({ params }: PageProps) => { - const address = params?.address as string; - - if (isZeroAddress(address)) return null; - - const contractData: { bytecode: string; assembly: string } | null = await getContractData(address); - return ; -}; - -export default AddressPage; diff --git a/packages/nextjs/app/blockexplorer/layout.tsx b/packages/nextjs/app/blockexplorer/layout.tsx deleted file mode 100644 index 1abc7ec..0000000 --- a/packages/nextjs/app/blockexplorer/layout.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { getMetadata } from "~~/utils/scaffold-eth/getMetadata"; - -export const metadata = getMetadata({ - title: "Block Explorer", - description: "Block Explorer created with 🏗 Scaffold-ETH 2", -}); - -const BlockExplorerLayout = ({ children }: { children: React.ReactNode }) => { - return <>{children}; -}; - -export default BlockExplorerLayout; diff --git a/packages/nextjs/app/blockexplorer/page.tsx b/packages/nextjs/app/blockexplorer/page.tsx deleted file mode 100644 index 61e6fc6..0000000 --- a/packages/nextjs/app/blockexplorer/page.tsx +++ /dev/null @@ -1,83 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { PaginationButton, SearchBar, TransactionsTable } from "./_components"; -import type { NextPage } from "next"; -import { hardhat } from "viem/chains"; -import { useFetchBlocks } from "~~/hooks/scaffold-eth"; -import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork"; -import { notification } from "~~/utils/scaffold-eth"; - -const BlockExplorer: NextPage = () => { - const { blocks, transactionReceipts, currentPage, totalBlocks, setCurrentPage, error } = useFetchBlocks(); - const { targetNetwork } = useTargetNetwork(); - const [isLocalNetwork, setIsLocalNetwork] = useState(true); - const [hasError, setHasError] = useState(false); - - useEffect(() => { - if (targetNetwork.id !== hardhat.id) { - setIsLocalNetwork(false); - } - }, [targetNetwork.id]); - - useEffect(() => { - if (targetNetwork.id === hardhat.id && error) { - setHasError(true); - } - }, [targetNetwork.id, error]); - - useEffect(() => { - if (!isLocalNetwork) { - notification.error( - <> -

- targeNetwork is not localhost -

-

- - You are on {targetNetwork.name} .This - block explorer is only for localhost. -

-

- - You can use{" "} - - {targetNetwork.blockExplorers?.default.name} - {" "} - instead -

- , - ); - } - }, [ - isLocalNetwork, - targetNetwork.blockExplorers?.default.name, - targetNetwork.blockExplorers?.default.url, - targetNetwork.name, - ]); - - useEffect(() => { - if (hasError) { - notification.error( - <> -

Cannot connect to local provider

-

- - Did you forget to run yarn chain ? -

-

- - Or you can change targetNetwork in{" "} - scaffold.config.ts -

- , - ); - } - }, [hasError]); - - return ( -
- - - -
- ); -}; - -export default BlockExplorer; diff --git a/packages/nextjs/app/blockexplorer/transaction/[txHash]/page.tsx b/packages/nextjs/app/blockexplorer/transaction/[txHash]/page.tsx deleted file mode 100644 index 3a49def..0000000 --- a/packages/nextjs/app/blockexplorer/transaction/[txHash]/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import TransactionComp from "../_components/TransactionComp"; -import type { NextPage } from "next"; -import { Hash } from "viem"; -import { isZeroAddress } from "~~/utils/scaffold-eth/common"; - -type PageProps = { - params: { txHash?: Hash }; -}; - -export function generateStaticParams() { - // An workaround to enable static exports in Next.js, generating single dummy page. - return [{ txHash: "0x0000000000000000000000000000000000000000" }]; -} -const TransactionPage: NextPage = ({ params }: PageProps) => { - const txHash = params?.txHash as Hash; - - if (isZeroAddress(txHash)) return null; - - return ; -}; - -export default TransactionPage; diff --git a/packages/nextjs/app/blockexplorer/transaction/_components/TransactionComp.tsx b/packages/nextjs/app/blockexplorer/transaction/_components/TransactionComp.tsx deleted file mode 100644 index 848f2e9..0000000 --- a/packages/nextjs/app/blockexplorer/transaction/_components/TransactionComp.tsx +++ /dev/null @@ -1,148 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { useRouter } from "next/navigation"; -import { Hash, Transaction, TransactionReceipt, formatEther, formatUnits } from "viem"; -import { hardhat } from "viem/chains"; -import { usePublicClient } from "wagmi"; -import { Address } from "~~/components/scaffold-eth"; -import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork"; -import { decodeTransactionData, getFunctionDetails } from "~~/utils/scaffold-eth"; -import { replacer } from "~~/utils/scaffold-eth/common"; - -const TransactionComp = ({ txHash }: { txHash: Hash }) => { - const client = usePublicClient({ chainId: hardhat.id }); - const router = useRouter(); - const [transaction, setTransaction] = useState(); - const [receipt, setReceipt] = useState(); - const [functionCalled, setFunctionCalled] = useState(); - - const { targetNetwork } = useTargetNetwork(); - - useEffect(() => { - if (txHash && client) { - const fetchTransaction = async () => { - const tx = await client.getTransaction({ hash: txHash }); - const receipt = await client.getTransactionReceipt({ hash: txHash }); - - const transactionWithDecodedData = decodeTransactionData(tx); - setTransaction(transactionWithDecodedData); - setReceipt(receipt); - - const functionCalled = transactionWithDecodedData.input.substring(0, 10); - setFunctionCalled(functionCalled); - }; - - fetchTransaction(); - } - }, [client, txHash]); - - return ( -
- - {transaction ? ( -
-

Transaction Details

{" "} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Transaction Hash: - {transaction.hash}
- Block Number: - {Number(transaction.blockNumber)}
- From: - -
-
- To: - - {!receipt?.contractAddress ? ( - transaction.to &&
- ) : ( - - Contract Creation: -
- - )} -
- Value: - - {formatEther(transaction.value)} {targetNetwork.nativeCurrency.symbol} -
- Function called: - -
- {functionCalled === "0x" ? ( - "This transaction did not call any function." - ) : ( - <> - {getFunctionDetails(transaction)} - {functionCalled} - - )} -
-
- Gas Price: - {formatUnits(transaction.gasPrice || 0n, 9)} Gwei
- Data: - -