Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base challenge next 14 migration #126

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"fork": "yarn workspace @se-2/hardhat fork",
"deploy": "yarn workspace @se-2/hardhat deploy",
"verify": "yarn workspace @se-2/hardhat verify",
"hardhat-verify": "yarn workspace @se-2/hardhat hardhat-verify",
"compile": "yarn workspace @se-2/hardhat compile",
"generate": "yarn workspace @se-2/hardhat generate",
"hardhat:lint": "yarn workspace @se-2/hardhat lint",
Expand All @@ -26,7 +27,8 @@
"next:check-types": "yarn workspace @se-2/nextjs check-types",
"postinstall": "husky install",
"precommit": "lint-staged",
"vercel": "yarn workspace @se-2/nextjs vercel"
"vercel": "yarn workspace @se-2/nextjs vercel",
"vercel:yolo": "yarn workspace @se-2/nextjs vercel:yolo"
},
"packageManager": "yarn@3.2.3",
"devDependencies": {
Expand Down
6 changes: 4 additions & 2 deletions packages/hardhat/deploy/00_deploy_your_contract.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { Contract } from "ethers";

/**
* Deploys a contract named "YourContract" using the deployer account and
Expand Down Expand Up @@ -31,8 +32,9 @@ const deployYourContract: DeployFunction = async function (hre: HardhatRuntimeEn
autoMine: true,
});

// Get the deployed contract
// const yourContract = await hre.ethers.getContract("YourContract", deployer);
// Get the deployed contract to interact with it after deploying.
const yourContract = await hre.ethers.getContract<Contract>("YourContract", deployer);
console.log("👋 Initial greeting:", await yourContract.greeting());
};

export default deployYourContract;
Expand Down
78 changes: 63 additions & 15 deletions packages/hardhat/deploy/99_generateTsAbis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,22 @@
* This script generates the file containing the contracts Abi definitions.
* These definitions are used to derive the types needed in the custom scaffold-eth hooks, for example.
* This script should run as the last deploy script.
* */
*/

import * as fs from "fs";
import prettier from "prettier";
import { DeployFunction } from "hardhat-deploy/types";

const generatedContractComment = `
/**
* This file is autogenerated by Scaffold-ETH.
* You should not edit it manually or your changes might be overwritten.
*/
`;

const DEPLOYMENTS_DIR = "./deployments";
const ARTIFACTS_DIR = "./artifacts";

function getDirectories(path: string) {
return fs
.readdirSync(path, { withFileTypes: true })
Expand All @@ -24,7 +34,46 @@ function getContractNames(path: string) {
.map(dirent => dirent.name.split(".")[0]);
}

const DEPLOYMENTS_DIR = "./deployments";
function getActualSourcesForContract(sources: Record<string, any>, contractName: string) {
for (const sourcePath of Object.keys(sources)) {
const sourceName = sourcePath.split("/").pop()?.split(".sol")[0];
if (sourceName === contractName) {
const contractContent = sources[sourcePath].content as string;
const regex = /contract\s+(\w+)\s+is\s+([^{}]+)\{/;
const match = contractContent.match(regex);

if (match) {
const inheritancePart = match[2];
// Split the inherited contracts by commas to get the list of inherited contracts
const inheritedContracts = inheritancePart.split(",").map(contract => `${contract.trim()}.sol`);

return inheritedContracts;
}
return [];
}
}
return [];
}

function getInheritedFunctions(sources: Record<string, any>, contractName: string) {
const actualSources = getActualSourcesForContract(sources, contractName);
const inheritedFunctions = {} as Record<string, any>;

for (const sourceContractName of actualSources) {
const sourcePath = Object.keys(sources).find(key => key.includes(`/${sourceContractName}`));
if (sourcePath) {
const sourceName = sourcePath?.split("/").pop()?.split(".sol")[0];
const { abi } = JSON.parse(fs.readFileSync(`${ARTIFACTS_DIR}/${sourcePath}/${sourceName}.json`).toString());
for (const functionAbi of abi) {
if (functionAbi.type === "function") {
inheritedFunctions[functionAbi.name] = sourcePath;
}
}
}
}

return inheritedFunctions;
}

function getContractDataFromDeployments() {
if (!fs.existsSync(DEPLOYMENTS_DIR)) {
Expand All @@ -35,18 +84,13 @@ function getContractDataFromDeployments() {
const chainId = fs.readFileSync(`${DEPLOYMENTS_DIR}/${chainName}/.chainId`).toString();
const contracts = {} as Record<string, any>;
for (const contractName of getContractNames(`${DEPLOYMENTS_DIR}/${chainName}`)) {
const { abi, address } = JSON.parse(
const { abi, address, metadata } = JSON.parse(
fs.readFileSync(`${DEPLOYMENTS_DIR}/${chainName}/${contractName}.json`).toString(),
);
contracts[contractName] = { address, abi };
const inheritedFunctions = getInheritedFunctions(JSON.parse(metadata).sources, contractName);
contracts[contractName] = { address, abi, inheritedFunctions };
}
output[chainId] = [
{
chainId,
name: chainName,
contracts,
},
];
output[chainId] = contracts;
}
return output;
}
Expand All @@ -56,7 +100,7 @@ function getContractDataFromDeployments() {
* This script should be run last.
*/
const generateTsAbis: DeployFunction = async function () {
const TARGET_DIR = "../nextjs/generated/";
const TARGET_DIR = "../nextjs/contracts/";
const allContractsData = getContractDataFromDeployments();

const fileContent = Object.entries(allContractsData).reduce((content, [chainId, chainConfig]) => {
Expand All @@ -68,9 +112,13 @@ const generateTsAbis: DeployFunction = async function () {
}
fs.writeFileSync(
`${TARGET_DIR}deployedContracts.ts`,
prettier.format(`const contracts = {${fileContent}} as const; \n\n export default contracts`, {
parser: "typescript",
}),
prettier.format(
`${generatedContractComment} import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract"; \n\n
const deployedContracts = {${fileContent}} as const; \n\n export default deployedContracts satisfies GenericContractsDeclaration`,
{
parser: "typescript",
},
),
);

console.log(`📝 Updated TypeScript contract definition file on ${TARGET_DIR}deployedContracts.ts`);
Expand Down
50 changes: 35 additions & 15 deletions packages/hardhat/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import * as dotenv from "dotenv";
dotenv.config();
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import "@nomicfoundation/hardhat-ethers";
import "@nomicfoundation/hardhat-chai-matchers";
import "@typechain/hardhat";
import "hardhat-gas-reporter";
import "solidity-coverage";
import "@nomicfoundation/hardhat-verify";
import "hardhat-deploy";
import "@matterlabs/hardhat-zksync-solc";
import "@matterlabs/hardhat-zksync-verify";
import "hardhat-deploy-ethers";

// If not set, it uses ours Alchemy's default API key.
// You can get your own at https://dashboard.alchemyapi.io
Expand Down Expand Up @@ -86,18 +90,6 @@ const config: HardhatUserConfig = {
url: `https://polygonzkevm-testnet.g.alchemy.com/v2/${providerApiKey}`,
accounts: [deployerPrivateKey],
},
zkSyncTestnet: {
url: "https://testnet.era.zksync.dev",
zksync: true,
accounts: [deployerPrivateKey],
verifyURL: "https://zksync2-testnet-explorer.zksync.dev/contract_verification",
},
zkSync: {
url: "https://mainnet.era.zksync.io",
zksync: true,
accounts: [deployerPrivateKey],
verifyURL: "https://zksync2-mainnet-explorer.zksync.io/contract_verification",
},
gnosis: {
url: "https://rpc.gnosischain.com",
accounts: [deployerPrivateKey],
Expand All @@ -114,12 +106,40 @@ const config: HardhatUserConfig = {
url: "https://goerli.base.org",
accounts: [deployerPrivateKey],
},
baseSepolia: {
url: "https://sepolia.base.org",
accounts: [deployerPrivateKey],
},
scrollSepolia: {
url: "https://sepolia-rpc.scroll.io",
accounts: [deployerPrivateKey],
},
scroll: {
url: "https://rpc.scroll.io",
accounts: [deployerPrivateKey],
},
pgn: {
url: "https://rpc.publicgoods.network",
accounts: [deployerPrivateKey],
},
pgnTestnet: {
url: "https://sepolia.publicgoods.network",
accounts: [deployerPrivateKey],
},
},
// configuration for harhdat-verify plugin
etherscan: {
apiKey: `${etherscanApiKey}`,
},
// configuration for etherscan-verify from hardhat-deploy plugin
verify: {
etherscan: {
apiKey: `${etherscanApiKey}`,
},
},
sourcify: {
enabled: false,
},
};

export default config;
24 changes: 12 additions & 12 deletions packages/hardhat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,18 @@
"lint": "eslint --config ./.eslintrc.json --ignore-path ./.eslintignore ./*.ts ./deploy/**/*.ts ./scripts/**/*.ts ./test/**/*.ts",
"lint-staged": "eslint --config ./.eslintrc.json --ignore-path ./.eslintignore",
"test": "REPORT_GAS=true hardhat test --network hardhat",
"verify": "hardhat etherscan-verify"
"verify": "hardhat etherscan-verify",
"hardhat-verify": "hardhat verify"
},
"devDependencies": {
"@ethersproject/abi": "^5.7.0",
"@ethersproject/providers": "^5.7.1",
"@matterlabs/hardhat-zksync-solc": "^0.3.17",
"@matterlabs/hardhat-zksync-verify": "^0.1.8",
"@nomicfoundation/hardhat-chai-matchers": "^1.0.3",
"@nomicfoundation/hardhat-chai-matchers": "^2.0.3",
"@nomicfoundation/hardhat-ethers": "^3.0.5",
"@nomicfoundation/hardhat-network-helpers": "^1.0.6",
"@nomicfoundation/hardhat-toolbox": "^2.0.0",
"@nomiclabs/hardhat-ethers": "npm:hardhat-deploy-ethers@^0.3.0-beta.13",
"@nomiclabs/hardhat-etherscan": "^3.1.0",
"@nomicfoundation/hardhat-verify": "^2.0.3",
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.3",
"@typechain/hardhat": "^9.1.0",
"@types/eslint": "^8",
"@types/mocha": "^9.1.1",
"@types/prettier": "^2",
Expand All @@ -35,18 +33,20 @@
"eslint": "^8.26.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"ethers": "^5.7.1",
"hardhat": "^2.17.3",
"hardhat-deploy": "^0.11.26",
"ethers": "^6.10.0",
"hardhat": "^2.19.4",
"hardhat-deploy": "^0.11.45",
"hardhat-deploy-ethers": "^0.4.1",
"hardhat-gas-reporter": "^1.0.9",
"prettier": "^2.8.4",
"solidity-coverage": "^0.8.2",
"solidity-coverage": "^0.8.5",
"ts-node": "^10.9.1",
"typechain": "^8.1.0",
"typescript": "^5.1.6"
},
"dependencies": {
"@openzeppelin/contracts": "^4.8.1",
"@typechain/ethers-v6": "^0.5.1",
"dotenv": "^16.0.3",
"envfile": "^6.18.0",
"qrcode": "^1.5.1"
Expand Down
5 changes: 3 additions & 2 deletions packages/hardhat/scripts/listAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ async function main() {
try {
const network = availableNetworks[networkName];
if (!("url" in network)) continue;
const provider = new ethers.providers.JsonRpcProvider(network.url);
const provider = new ethers.JsonRpcProvider(network.url);
await provider._detectNetwork();
const balance = await provider.getBalance(address);
console.log("--", networkName, "-- 📡");
console.log(" balance:", +ethers.utils.formatEther(balance));
console.log(" balance:", +ethers.formatEther(balance));
console.log(" nonce:", +(await provider.getTransactionCount(address)));
} catch (e) {
console.log("Can't connect to network", networkName);
Expand Down
28 changes: 28 additions & 0 deletions packages/hardhat/test/YourContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { expect } from "chai";
import { ethers } from "hardhat";
import { YourContract } from "../typechain-types";

describe("YourContract", function () {
// We define a fixture to reuse the same setup in every test.

let yourContract: YourContract;
before(async () => {
const [owner] = await ethers.getSigners();
const yourContractFactory = await ethers.getContractFactory("YourContract");
yourContract = (await yourContractFactory.deploy(owner.address)) as YourContract;
await yourContract.waitForDeployment();
});

describe("Deployment", function () {
it("Should have the right message on deploy", async function () {
expect(await yourContract.greeting()).to.equal("Building Unstoppable Apps!!!");
});

it("Should allow setting a new message", async function () {
const newGreeting = "Learn Scaffold-ETH 2! :)";

await yourContract.setGreeting(newGreeting);
expect(await yourContract.greeting()).to.equal(newGreeting);
});
});
});
35 changes: 35 additions & 0 deletions packages/nextjs/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" />
<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,13 +1,15 @@
"use client";

import { useEffect, useState } from "react";
import { createPublicClient, http, toHex } from "viem";
import { hardhat } from "wagmi/chains";
import { Address, createPublicClient, http, toHex } from "viem";
import { hardhat } from "viem/chains";

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 Down
12 changes: 12 additions & 0 deletions packages/nextjs/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>
);
};
Loading