Skip to content

Commit

Permalink
update scaffold eth2 version
Browse files Browse the repository at this point in the history
  • Loading branch information
olivmath committed Sep 23, 2024
1 parent 14fe310 commit 03ca9d2
Show file tree
Hide file tree
Showing 145 changed files with 5,324 additions and 4,010 deletions.
13 changes: 13 additions & 0 deletions ui/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Template for NextJS environment variables.

# For local development, copy this file, rename it to .env.local, and fill in the values.
# When deploying live, you'll need to store the vars in Vercel/System config.

# If not set, we provide default values (check `scaffold.config.ts`) so developers can start prototyping out of the box,
# but we recommend getting your own API Keys for Production Apps.

# To access the values stored in this env file you can use: process.env.VARIABLENAME
# You'll need to prefix the variables names with NEXT_PUBLIC_ if you want to access them on the client side.
# More info: https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables
NEXT_PUBLIC_ALCHEMY_API_KEY=
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=
3 changes: 1 addition & 2 deletions ui/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
{
"endOfLine": "auto"
}
],
"@next/next/no-page-custom-font": ["off"]
]
}
}
8 changes: 2 additions & 6 deletions ui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# next.js
/.next/
/out/
.vercel

# production
/build
Expand All @@ -26,16 +27,11 @@ yarn-error.log*
.pnpm-debug.log*

# local env files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# vercel
.vercel

# typescript
*.tsbuildinfo

# deploy update
deployedContracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ type AddressCodeTabProps = {
};

export const AddressCodeTab = ({ bytecode, assembly }: AddressCodeTabProps) => {
const formattedAssembly = assembly.split(" ").join("\n");
const formattedAssembly = Array.from(assembly.matchAll(/\w+( 0x[a-fA-F0-9]+)?/g))
.map(it => it[0])
.join("\n");

return (
<div className="flex flex-col gap-3 p-4">
Expand Down
35 changes: 35 additions & 0 deletions ui/app/blockexplorer/_components/AddressComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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 (
<div className="m-10 mb-20">
<div className="flex justify-start mb-5">
<BackButton />
</div>
<div className="col-span-5 grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-10">
<div className="col-span-1 flex flex-col">
<div className="bg-base-100 border-base-300 border shadow-md shadow-secondary rounded-3xl px-6 lg:px-8 mb-6 space-y-1 py-4 overflow-x-auto">
<div className="flex">
<div className="flex flex-col gap-1">
<Address address={address} format="long" onlyEnsOrAddress />
<div className="flex gap-1 items-center">
<span className="font-bold text-sm">Balance:</span>
<Balance address={address} className="text" />
</div>
</div>
</div>
</div>
</div>
</div>
<ContractTabs address={address} contractData={contractData} />
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Address } from "viem";
import { useContractLogs } from "~~/hooks/scaffold-eth";
import { replacer } from "~~/utils/scaffold-eth/common";

export const AddressLogsTab = ({ address }: { address: string }) => {
export const AddressLogsTab = ({ address }: { address: Address }) => {
const contractLogs = useContractLogs(address);

return (
Expand All @@ -9,7 +11,7 @@ export const AddressLogsTab = ({ address }: { address: string }) => {
<pre className="px-5 whitespace-pre-wrap break-words">
{contractLogs.map((log, i) => (
<div key={i}>
<strong>Log:</strong> {JSON.stringify(log, null, 2)}
<strong>Log:</strong> {JSON.stringify(log, replacer, 2)}
</div>
))}
</pre>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
"use client";

import { useEffect, useState } from "react";
import { localhost } from "wagmi/chains";
import { getLocalProvider } from "~~/utils/scaffold-eth";
import { Address, createPublicClient, http, toHex } from "viem";
import { hardhat } from "viem/chains";

const provider = getLocalProvider(localhost);
const publicClient = createPublicClient({
chain: hardhat,
transport: http(),
});

export const AddressStorageTab = ({ address }: { address: string }) => {
export const AddressStorageTab = ({ address }: { address: Address }) => {
const [storage, setStorage] = useState<string[]>([]);

useEffect(() => {
Expand All @@ -14,7 +19,10 @@ export const AddressStorageTab = ({ address }: { address: string }) => {
let idx = 0;

while (true) {
const storageAtPosition = await provider?.getStorageAt(address, idx);
const storageAtPosition = await publicClient.getStorageAt({
address: address,
slot: toHex(idx),
});

if (storageAtPosition === "0x" + "0".repeat(64)) break;

Expand Down
12 changes: 12 additions & 0 deletions ui/app/blockexplorer/_components/BackButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use client";

import { useRouter } from "next/navigation";

export const BackButton = () => {
const router = useRouter();
return (
<button className="btn btn-sm btn-primary" onClick={() => router.back()}>
Back
</button>
);
};
92 changes: 92 additions & 0 deletions ui/app/blockexplorer/_components/ContractTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"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 && (
<div className="tabs tabs-lifted w-min">
<button
className={`tab ${activeTab === "transactions" ? "tab-active" : ""}`}
onClick={() => setActiveTab("transactions")}
>
Transactions
</button>
<button className={`tab ${activeTab === "code" ? "tab-active" : ""}`} onClick={() => setActiveTab("code")}>
Code
</button>
<button
className={`tab ${activeTab === "storage" ? "tab-active" : ""}`}
onClick={() => setActiveTab("storage")}
>
Storage
</button>
<button className={`tab ${activeTab === "logs" ? "tab-active" : ""}`} onClick={() => setActiveTab("logs")}>
Logs
</button>
</div>
)}
{activeTab === "transactions" && (
<div className="pt-4">
<TransactionsTable blocks={filteredBlocks} transactionReceipts={transactionReceipts} />
<PaginationButton
currentPage={currentPage}
totalItems={Number(totalBlocks)}
setCurrentPage={setCurrentPage}
/>
</div>
)}
{activeTab === "code" && contractData && (
<AddressCodeTab bytecode={contractData.bytecode} assembly={contractData.assembly} />
)}
{activeTab === "storage" && <AddressStorageTab address={address} />}
{activeTab === "logs" && <AddressLogsTab address={address} />}
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/24/outline";

interface PaginationButtonProps {
type PaginationButtonProps = {
currentPage: number;
totalItems: number;
setCurrentPage: (page: number) => void;
}
};

const ITEMS_PER_PAGE = 20;

Expand All @@ -18,7 +18,7 @@ export const PaginationButton = ({ currentPage, totalItems, setCurrentPage }: Pa
if (isNextButtonDisabled && isPrevButtonDisabled) return null;

return (
<div className="mt-5 justify-end flex gap-3">
<div className="mt-5 justify-end flex gap-3 mx-5">
<button
className={`btn btn-sm ${prevButtonClass}`}
disabled={isPrevButtonDisabled}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
"use client";

import { useState } from "react";
import { useRouter } from "next/router";
import { ethers } from "ethers";
import { localhost } from "wagmi/chains";
import { getLocalProvider } from "~~/utils/scaffold-eth";
import DOMPurify from "dompurify";
import { useRouter } from "next/navigation";
import { isAddress, isHex } from "viem";
import { hardhat } from "viem/chains";
import { usePublicClient } from "wagmi";

const provider = getLocalProvider(localhost);
export const SearchBar = () => {
const [searchInput, setSearchInput] = useState("");
const router = useRouter();

const client = usePublicClient({ chainId: hardhat.id });

const handleSearch = async (event: React.FormEvent) => {
event.preventDefault();
const sanitizedInput = DOMPurify.sanitize(searchInput);
if (ethers.utils.isHexString(sanitizedInput)) {
if (isHex(searchInput)) {
try {
const tx = await provider?.getTransaction(sanitizedInput);
const tx = await client?.getTransaction({ hash: searchInput });
if (tx) {
router.push(`/blockexplorer/transaction/${sanitizedInput}`);
router.push(`/blockexplorer/transaction/${searchInput}`);
return;
}
} catch (error) {
console.error("Failed to fetch transaction:", error);
}
}

if (ethers.utils.isAddress(sanitizedInput)) {
router.push(`/blockexplorer/address/${sanitizedInput}`);
if (isAddress(searchInput)) {
router.push(`/blockexplorer/address/${searchInput}`);
return;
}
};

return (
<form onSubmit={handleSearch} className="flex items-center justify-end mb-5 space-x-3">
<form onSubmit={handleSearch} className="flex items-center justify-end mb-5 space-x-3 mx-5">
<input
className="border-primary bg-base-100 text-base-content p-2 mr-2 w-full md:w-1/2 lg:w-1/3 rounded-md shadow-md focus:outline-none focus:ring-2 focus:ring-accent"
type="text"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"use client";

import { useState } from "react";
import Link from "next/link";
import { CopyToClipboard } from "react-copy-to-clipboard";
import CopyToClipboard from "react-copy-to-clipboard";
import { CheckCircleIcon, DocumentDuplicateIcon } from "@heroicons/react/24/outline";

export const TransactionHash = ({ hash }: { hash: string }) => {
Expand Down
Loading

0 comments on commit 03ca9d2

Please sign in to comment.