From 41adf1d34393fc809527f45de5e123d4b0c9ec04 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 15 Apr 2024 15:17:42 +0100 Subject: [PATCH 01/62] feat(cli): verify command --- packages/cli/src/commands/index.ts | 2 ++ packages/cli/src/commands/verify.ts | 34 +++++++++++++++++++++++++++++ packages/cli/src/verify.ts | 32 +++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 packages/cli/src/commands/verify.ts create mode 100644 packages/cli/src/verify.ts diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index b00bf65dc0..7db9e57ed6 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -14,6 +14,7 @@ import setVersion from "./set-version"; import test from "./test"; import trace from "./trace"; import devContracts from "./dev-contracts"; +import verify from "./verify"; // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options export const commands: CommandModule[] = [ @@ -30,4 +31,5 @@ export const commands: CommandModule[] = [ trace, devContracts, abiTs, + verify, ]; diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts new file mode 100644 index 0000000000..5029f3b212 --- /dev/null +++ b/packages/cli/src/commands/verify.ts @@ -0,0 +1,34 @@ +import type { CommandModule } from "yargs"; +import { verify } from "../verify"; +import { logError } from "../utils/errors"; +import { Hex } from "viem"; + +type Options = { + profile?: string; +}; + +const commandModule: CommandModule = { + command: "verify", + + describe: "Verify contracts", + + builder(yargs) { + return yargs.options({ + profile: { type: "string", desc: "The foundry profile to use" }, + worldAddress: { type: "string", desc: "Deploy to an existing World at the given address" }, + }); + }, + + async handler({ profile, worldAddress }) { + // Wrap in try/catch, because yargs seems to swallow errors + try { + await verify({ worldAddress: worldAddress as Hex, foundryProfile: profile }); + } catch (error) { + logError(error); + process.exit(1); + } + process.exit(0); + }, +}; + +export default commandModule; diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts new file mode 100644 index 0000000000..73bfe353a0 --- /dev/null +++ b/packages/cli/src/verify.ts @@ -0,0 +1,32 @@ +import { forge, getRpcUrl } from "@latticexyz/common/foundry"; +import { Hex, createWalletClient, http } from "viem"; +import { getSystems } from "./deploy/getSystems"; +import { getWorldDeploy } from "./deploy/getWorldDeploy"; + +type VerifyOptions = { + worldAddress: Hex; + foundryProfile?: string; +}; + +export async function verify({ + worldAddress, + foundryProfile = process.env.FOUNDRY_PROFILE, +}: VerifyOptions): Promise { + const rpc = await getRpcUrl(foundryProfile); + + const client = createWalletClient({ + transport: http(rpc), + }); + + const worldDeploy = await getWorldDeploy(client, worldAddress); + + const systems = await getSystems({ client, worldDeploy }); + + await Promise.all( + systems.map((system) => + forge(["verify-contract", system.address, system.name, "--verifier", "sourcify"], { + profile: foundryProfile, + }), + ), + ); +} From 8a95d3803d1bbef0cf33807daa77e5d856cacc92 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 15 Apr 2024 15:46:20 +0100 Subject: [PATCH 02/62] feat: testing example on holesky --- examples/minimal/packages/contracts/foundry.toml | 4 ++++ examples/minimal/packages/contracts/package.json | 4 +++- examples/minimal/packages/contracts/worlds.json | 6 +++++- packages/cli/src/verify.ts | 12 +++++++----- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/examples/minimal/packages/contracts/foundry.toml b/examples/minimal/packages/contracts/foundry.toml index 3eb96af5e6..3580e62ef6 100644 --- a/examples/minimal/packages/contracts/foundry.toml +++ b/examples/minimal/packages/contracts/foundry.toml @@ -22,3 +22,7 @@ fs_permissions = [{ access = "read", path = "./"}] [profile.lattice-testnet] eth_rpc_url = "https://follower.testnet-chain.linfra.xyz" + +[profile.holesky] +eth_rpc_url = "https://17000.rpc.thirdweb.com" +# eth_rpc_url = "https://ethereum-holesky.publicnode.com" diff --git a/examples/minimal/packages/contracts/package.json b/examples/minimal/packages/contracts/package.json index cb4a8c3286..60b1c4d790 100644 --- a/examples/minimal/packages/contracts/package.json +++ b/examples/minimal/packages/contracts/package.json @@ -6,6 +6,7 @@ "scripts": { "build": "mud build", "clean": "forge clean && rimraf src/codegen", + "deploy:holesky": "pnpm run build && mud deploy --profile=holesky", "deploy:local": "pnpm run build && mud deploy", "deploy:testnet": "pnpm run build && mud deploy --profile=lattice-testnet", "dev": "pnpm mud dev-contracts", @@ -13,7 +14,8 @@ "lint": "pnpm run prettier && pnpm run solhint", "prettier": "prettier --write 'src/**/*.sol'", "solhint": "solhint --config ./.solhint.json 'src/**/*.sol' --fix", - "test": "mud test" + "test": "mud test", + "verify": "pnpm mud verify --profile=holesky --worldAddress=0xb1eca382fe27df86db5fce82830fbd3cb942f05b" }, "devDependencies": { "@latticexyz/cli": "link:../../../../packages/cli", diff --git a/examples/minimal/packages/contracts/worlds.json b/examples/minimal/packages/contracts/worlds.json index 2d47ae4158..3e7ec7daf5 100644 --- a/examples/minimal/packages/contracts/worlds.json +++ b/examples/minimal/packages/contracts/worlds.json @@ -3,7 +3,11 @@ "address": "0xb51cE08442de2aB60f327566db833eed15B47b60", "blockNumber": 21817970 }, + "17000": { + "address": "0xb1eca382fe27df86db5fce82830fbd3cb942f05b", + "blockNumber": 1352275 + }, "31337": { - "address": "0x6e9474e9c83676b9a71133ff96db43e7aa0a4342" + "address": "0x8ac4e60625d49ab7ab0055c598dd62754e71a089" } } \ No newline at end of file diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 73bfe353a0..67f8336c41 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -23,10 +23,12 @@ export async function verify({ const systems = await getSystems({ client, worldDeploy }); await Promise.all( - systems.map((system) => - forge(["verify-contract", system.address, system.name, "--verifier", "sourcify"], { - profile: foundryProfile, - }), - ), + systems + .filter((system) => system.name === "increment") + .map((system) => + forge(["verify-contract", system.address, "IncrementSystem", "--verifier", "sourcify"], { + profile: foundryProfile, + }), + ), ); } From ed21e9256053f4589d4a7f5b0c0bbbba56337598 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 15 Apr 2024 15:55:10 +0100 Subject: [PATCH 03/62] chore: remove filter --- packages/cli/src/verify.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 67f8336c41..73bfe353a0 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -23,12 +23,10 @@ export async function verify({ const systems = await getSystems({ client, worldDeploy }); await Promise.all( - systems - .filter((system) => system.name === "increment") - .map((system) => - forge(["verify-contract", system.address, "IncrementSystem", "--verifier", "sourcify"], { - profile: foundryProfile, - }), - ), + systems.map((system) => + forge(["verify-contract", system.address, system.name, "--verifier", "sourcify"], { + profile: foundryProfile, + }), + ), ); } From 477683642561ffe22890135f6dbf18ceb9c80d64 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 15 Apr 2024 18:44:14 +0100 Subject: [PATCH 04/62] feat: verify based on folder --- .../minimal/packages/contracts/package.json | 2 +- packages/cli/src/commands/verify.ts | 6 +- packages/cli/src/verify.ts | 61 +++++++++++++------ 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/examples/minimal/packages/contracts/package.json b/examples/minimal/packages/contracts/package.json index 60b1c4d790..ea7cc7b821 100644 --- a/examples/minimal/packages/contracts/package.json +++ b/examples/minimal/packages/contracts/package.json @@ -15,7 +15,7 @@ "prettier": "prettier --write 'src/**/*.sol'", "solhint": "solhint --config ./.solhint.json 'src/**/*.sol' --fix", "test": "mud test", - "verify": "pnpm mud verify --profile=holesky --worldAddress=0xb1eca382fe27df86db5fce82830fbd3cb942f05b" + "verify": "pnpm mud verify --profile=holesky" }, "devDependencies": { "@latticexyz/cli": "link:../../../../packages/cli", diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 5029f3b212..29ef5425c3 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -1,7 +1,6 @@ import type { CommandModule } from "yargs"; import { verify } from "../verify"; import { logError } from "../utils/errors"; -import { Hex } from "viem"; type Options = { profile?: string; @@ -15,14 +14,13 @@ const commandModule: CommandModule = { builder(yargs) { return yargs.options({ profile: { type: "string", desc: "The foundry profile to use" }, - worldAddress: { type: "string", desc: "Deploy to an existing World at the given address" }, }); }, - async handler({ profile, worldAddress }) { + async handler({ profile }) { // Wrap in try/catch, because yargs seems to swallow errors try { - await verify({ worldAddress: worldAddress as Hex, foundryProfile: profile }); + await verify({ foundryProfile: profile }); } catch (error) { logError(error); process.exit(1); diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 73bfe353a0..ec2204a5b2 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,32 +1,57 @@ import { forge, getRpcUrl } from "@latticexyz/common/foundry"; -import { Hex, createWalletClient, http } from "viem"; -import { getSystems } from "./deploy/getSystems"; -import { getWorldDeploy } from "./deploy/getWorldDeploy"; +import { Hex, createWalletClient, getCreate2Address, http } from "viem"; +import { readFileSync, readdirSync } from "fs"; +import { salt } from "./deploy/common"; +import { ensureDeployer } from "./deploy/ensureDeployer"; +import { privateKeyToAccount } from "viem/accounts"; +import { MUDError } from "@latticexyz/common/errors"; type VerifyOptions = { - worldAddress: Hex; foundryProfile?: string; }; -export async function verify({ - worldAddress, - foundryProfile = process.env.FOUNDRY_PROFILE, -}: VerifyOptions): Promise { +async function verifyFolder(outPath: string, foundryProfile: string | undefined, deployerAddress: Hex) { + const folderNames = readdirSync(outPath); + + await Promise.all( + folderNames.map((name) => { + const fileNames = readdirSync(`out/${name}`); + + fileNames + .filter((filename) => filename.split(".").length === 2) // check that the file ends in .json + .map((filename) => { + const filePath = `out/${name}/${filename}`; + const bytecode = JSON.parse(readFileSync(filePath, "utf8")).bytecode.object as Hex; + const system = getCreate2Address({ from: deployerAddress, bytecode, salt }); + + forge(["verify-contract", system, filename, "--verifier", "sourcify"], { + profile: foundryProfile, + }); + }); + }), + ); +} + +export async function verify({ foundryProfile = process.env.FOUNDRY_PROFILE }: VerifyOptions): Promise { + const privateKey = process.env.PRIVATE_KEY as Hex; + if (!privateKey) { + throw new MUDError( + `Missing PRIVATE_KEY environment variable. +Run 'echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env' +in your contracts directory to use the default anvil private key.`, + ); + } + const rpc = await getRpcUrl(foundryProfile); const client = createWalletClient({ transport: http(rpc), + account: privateKeyToAccount(privateKey), }); - const worldDeploy = await getWorldDeploy(client, worldAddress); - - const systems = await getSystems({ client, worldDeploy }); + const deployerAddress = await ensureDeployer(client); - await Promise.all( - systems.map((system) => - forge(["verify-contract", system.address, system.name, "--verifier", "sourcify"], { - profile: foundryProfile, - }), - ), - ); + verifyFolder("out", foundryProfile, deployerAddress); + verifyFolder("node_modules/@latticexyz/world/out", foundryProfile, deployerAddress); + verifyFolder("node_modules/@latticexyz/world-modules/out", foundryProfile, deployerAddress); } From 20ba4efc06c66e0ce965829338260074b7b915c6 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 15 Apr 2024 20:27:49 +0100 Subject: [PATCH 05/62] refactor: get contracts --- packages/cli/src/commands/verify.ts | 16 ++++++- packages/cli/src/verify.ts | 69 ++++++++++++++++++----------- 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 29ef5425c3..0a4253e4d9 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -1,6 +1,11 @@ import type { CommandModule } from "yargs"; import { verify } from "../verify"; import { logError } from "../utils/errors"; +import { loadConfig } from "@latticexyz/config/node"; +import { WorldConfig } from "@latticexyz/world/internal"; +import { worldToV1 } from "@latticexyz/world/config/v2"; +import { resolveConfig } from "../deploy/resolveConfig"; +import { getOutDirectory, getSrcDirectory } from "@latticexyz/common/foundry"; type Options = { profile?: string; @@ -14,13 +19,22 @@ const commandModule: CommandModule = { builder(yargs) { return yargs.options({ profile: { type: "string", desc: "The foundry profile to use" }, + worldAddress: { type: "string", desc: "Deploy to an existing World at the given address" }, }); }, async handler({ profile }) { + const configV2 = (await loadConfig(undefined)) as WorldConfig; + const config = worldToV1(configV2); + + const srcDir = await getSrcDirectory(profile); + const outDir = await getOutDirectory(profile); + + const resolvedConfig = resolveConfig({ config, forgeSourceDir: srcDir, forgeOutDir: outDir }); + // Wrap in try/catch, because yargs seems to swallow errors try { - await verify({ foundryProfile: profile }); + await verify({ config: resolvedConfig, foundryProfile: profile }); } catch (error) { logError(error); process.exit(1); diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index ec2204a5b2..9b699ed931 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,38 +1,41 @@ import { forge, getRpcUrl } from "@latticexyz/common/foundry"; import { Hex, createWalletClient, getCreate2Address, http } from "viem"; -import { readFileSync, readdirSync } from "fs"; -import { salt } from "./deploy/common"; +import { Config, ConfigInput, salt } from "./deploy/common"; import { ensureDeployer } from "./deploy/ensureDeployer"; import { privateKeyToAccount } from "viem/accounts"; import { MUDError } from "@latticexyz/common/errors"; +import accessManagementSystemBuild from "@latticexyz/world/out/AccessManagementSystem.sol/AccessManagementSystem.json" assert { type: "json" }; +import balanceTransferSystemBuild from "@latticexyz/world/out/BalanceTransferSystem.sol/BalanceTransferSystem.json" assert { type: "json" }; +import batchCallSystemBuild from "@latticexyz/world/out/BatchCallSystem.sol/BatchCallSystem.json" assert { type: "json" }; +import registrationSystemBuild from "@latticexyz/world/out/RegistrationSystem.sol/RegistrationSystem.json" assert { type: "json" }; +import initModuleBuild from "@latticexyz/world/out/InitModule.sol/InitModule.json" assert { type: "json" }; +import worldFactoryBuild from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.json" assert { type: "json" }; +import { resourceToLabel } from "@latticexyz/common"; type VerifyOptions = { + config: Config; foundryProfile?: string; }; -async function verifyFolder(outPath: string, foundryProfile: string | undefined, deployerAddress: Hex) { - const folderNames = readdirSync(outPath); - - await Promise.all( - folderNames.map((name) => { - const fileNames = readdirSync(`out/${name}`); - - fileNames - .filter((filename) => filename.split(".").length === 2) // check that the file ends in .json - .map((filename) => { - const filePath = `out/${name}/${filename}`; - const bytecode = JSON.parse(readFileSync(filePath, "utf8")).bytecode.object as Hex; - const system = getCreate2Address({ from: deployerAddress, bytecode, salt }); - - forge(["verify-contract", system, filename, "--verifier", "sourcify"], { - profile: foundryProfile, - }); - }); - }), - ); +// The contracts that are deployed in ensureWorldFactory +const WORLD_FACTORY = [ + { name: "AccessManagementSystem", bytecode: accessManagementSystemBuild.bytecode.object as Hex }, + { name: "BalanceTransferSystem", bytecode: balanceTransferSystemBuild.bytecode.object as Hex }, + { name: "BatchCallSystem", bytecode: batchCallSystemBuild.bytecode.object as Hex }, + { name: "RegistrationSystem", bytecode: registrationSystemBuild.bytecode.object as Hex }, + { name: "InitModule", bytecode: initModuleBuild.bytecode.object as Hex }, + { name: "WorldFactory", bytecode: worldFactoryBuild.bytecode.object as Hex }, +]; + +async function verifyContract(foundryProfile: string | undefined, deployerAddress: Hex, name: string, bytecode: Hex) { + const system = getCreate2Address({ from: deployerAddress, bytecode, salt }); + + forge(["verify-contract", system, name, "--verifier", "sourcify"], { + profile: foundryProfile, + }); } -export async function verify({ foundryProfile = process.env.FOUNDRY_PROFILE }: VerifyOptions): Promise { +export async function verify({ config, foundryProfile = process.env.FOUNDRY_PROFILE }: VerifyOptions): Promise { const privateKey = process.env.PRIVATE_KEY as Hex; if (!privateKey) { throw new MUDError( @@ -51,7 +54,21 @@ in your contracts directory to use the default anvil private key.`, const deployerAddress = await ensureDeployer(client); - verifyFolder("out", foundryProfile, deployerAddress); - verifyFolder("node_modules/@latticexyz/world/out", foundryProfile, deployerAddress); - verifyFolder("node_modules/@latticexyz/world-modules/out", foundryProfile, deployerAddress); + const contracts = [ + ...config.libraries.map((library) => ({ + bytecode: library.prepareDeploy(deployerAddress, config.libraries).bytecode, + label: library.name, + })), + ...config.systems.map((system) => ({ + bytecode: system.prepareDeploy(deployerAddress, config.libraries).bytecode, + label: `${resourceToLabel(system)} system`, + })), + ...config.modules.map((mod) => ({ + bytecode: mod.prepareDeploy(deployerAddress, config.libraries).bytecode, + label: mod.name, + })), + ]; + + contracts.map(({ label, bytecode }) => verifyContract(foundryProfile, deployerAddress, label, bytecode)); + WORLD_FACTORY.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)); } From 3fe79c59da0128185283c5c94328eaaf70048691 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 15 Apr 2024 20:30:05 +0100 Subject: [PATCH 06/62] fix: promise.all --- packages/cli/src/verify.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 9b699ed931..9c831ce8e5 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -30,7 +30,7 @@ const WORLD_FACTORY = [ async function verifyContract(foundryProfile: string | undefined, deployerAddress: Hex, name: string, bytecode: Hex) { const system = getCreate2Address({ from: deployerAddress, bytecode, salt }); - forge(["verify-contract", system, name, "--verifier", "sourcify"], { + await forge(["verify-contract", system, name, "--verifier", "sourcify"], { profile: foundryProfile, }); } @@ -69,6 +69,10 @@ in your contracts directory to use the default anvil private key.`, })), ]; - contracts.map(({ label, bytecode }) => verifyContract(foundryProfile, deployerAddress, label, bytecode)); - WORLD_FACTORY.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)); + await Promise.all( + contracts.map(({ label, bytecode }) => verifyContract(foundryProfile, deployerAddress, label, bytecode)), + ); + await Promise.all( + WORLD_FACTORY.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), + ); } From 14fa5b6e23bc384222f3a7cffdf92d6fa195c30a Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 15 Apr 2024 20:31:21 +0100 Subject: [PATCH 07/62] fix: system --- packages/cli/src/verify.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 9c831ce8e5..2468098a86 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -61,7 +61,7 @@ in your contracts directory to use the default anvil private key.`, })), ...config.systems.map((system) => ({ bytecode: system.prepareDeploy(deployerAddress, config.libraries).bytecode, - label: `${resourceToLabel(system)} system`, + label: resourceToLabel(system), })), ...config.modules.map((mod) => ({ bytecode: mod.prepareDeploy(deployerAddress, config.libraries).bytecode, From 973ef3e0bbc334cafdf3192ee912bb56b992d3f3 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 15 Apr 2024 21:07:45 +0100 Subject: [PATCH 08/62] fix: get systems from world config --- packages/cli/src/commands/verify.ts | 25 +++++++++++++++++++++---- packages/cli/src/verify.ts | 24 ++++-------------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 0a4253e4d9..84219e802f 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -2,10 +2,11 @@ import type { CommandModule } from "yargs"; import { verify } from "../verify"; import { logError } from "../utils/errors"; import { loadConfig } from "@latticexyz/config/node"; -import { WorldConfig } from "@latticexyz/world/internal"; +import { WorldConfig, resolveWorldConfig } from "@latticexyz/world/internal"; import { worldToV1 } from "@latticexyz/world/config/v2"; -import { resolveConfig } from "../deploy/resolveConfig"; import { getOutDirectory, getSrcDirectory } from "@latticexyz/common/foundry"; +import { getExistingContracts } from "../utils/getExistingContracts"; +import { getContractData } from "../utils/getContractData"; type Options = { profile?: string; @@ -30,11 +31,27 @@ const commandModule: CommandModule = { const srcDir = await getSrcDirectory(profile); const outDir = await getOutDirectory(profile); - const resolvedConfig = resolveConfig({ config, forgeSourceDir: srcDir, forgeOutDir: outDir }); + const forgeSourceDir = srcDir; + const contractNames = getExistingContracts(forgeSourceDir).map(({ basename }) => basename); + + const resolvedWorldConfig = resolveWorldConfig(config, contractNames); + const systems = Object.keys(resolvedWorldConfig.systems).map((systemName) => { + const contractData = getContractData(`${systemName}.sol`, systemName, outDir); + + return { + systemName, + bytecode: contractData.bytecode, + }; + }); + + console.log(systems); // Wrap in try/catch, because yargs seems to swallow errors try { - await verify({ config: resolvedConfig, foundryProfile: profile }); + await verify({ + foundryProfile: profile, + systems, + }); } catch (error) { logError(error); process.exit(1); diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 2468098a86..e86768347e 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,6 +1,6 @@ import { forge, getRpcUrl } from "@latticexyz/common/foundry"; import { Hex, createWalletClient, getCreate2Address, http } from "viem"; -import { Config, ConfigInput, salt } from "./deploy/common"; +import { salt } from "./deploy/common"; import { ensureDeployer } from "./deploy/ensureDeployer"; import { privateKeyToAccount } from "viem/accounts"; import { MUDError } from "@latticexyz/common/errors"; @@ -10,11 +10,10 @@ import batchCallSystemBuild from "@latticexyz/world/out/BatchCallSystem.sol/Batc import registrationSystemBuild from "@latticexyz/world/out/RegistrationSystem.sol/RegistrationSystem.json" assert { type: "json" }; import initModuleBuild from "@latticexyz/world/out/InitModule.sol/InitModule.json" assert { type: "json" }; import worldFactoryBuild from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.json" assert { type: "json" }; -import { resourceToLabel } from "@latticexyz/common"; type VerifyOptions = { - config: Config; foundryProfile?: string; + systems: { systemName: string; bytecode: Hex }[]; }; // The contracts that are deployed in ensureWorldFactory @@ -35,7 +34,7 @@ async function verifyContract(foundryProfile: string | undefined, deployerAddres }); } -export async function verify({ config, foundryProfile = process.env.FOUNDRY_PROFILE }: VerifyOptions): Promise { +export async function verify({ foundryProfile = process.env.FOUNDRY_PROFILE, systems }: VerifyOptions): Promise { const privateKey = process.env.PRIVATE_KEY as Hex; if (!privateKey) { throw new MUDError( @@ -54,23 +53,8 @@ in your contracts directory to use the default anvil private key.`, const deployerAddress = await ensureDeployer(client); - const contracts = [ - ...config.libraries.map((library) => ({ - bytecode: library.prepareDeploy(deployerAddress, config.libraries).bytecode, - label: library.name, - })), - ...config.systems.map((system) => ({ - bytecode: system.prepareDeploy(deployerAddress, config.libraries).bytecode, - label: resourceToLabel(system), - })), - ...config.modules.map((mod) => ({ - bytecode: mod.prepareDeploy(deployerAddress, config.libraries).bytecode, - label: mod.name, - })), - ]; - await Promise.all( - contracts.map(({ label, bytecode }) => verifyContract(foundryProfile, deployerAddress, label, bytecode)), + systems.map(({ systemName, bytecode }) => verifyContract(foundryProfile, deployerAddress, systemName, bytecode)), ); await Promise.all( WORLD_FACTORY.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), From b7f082be2801688cada5d7be4eb0900dd3fc1126 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 15 Apr 2024 21:17:52 +0100 Subject: [PATCH 09/62] feat: modules --- packages/cli/src/commands/verify.ts | 19 +++++++++++++++---- packages/cli/src/verify.ts | 16 +++++++++++++--- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 84219e802f..da1ab5fc6f 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -7,6 +7,7 @@ import { worldToV1 } from "@latticexyz/world/config/v2"; import { getOutDirectory, getSrcDirectory } from "@latticexyz/common/foundry"; import { getExistingContracts } from "../utils/getExistingContracts"; import { getContractData } from "../utils/getContractData"; +import { defaultModuleContracts } from "../utils/defaultModuleContracts"; type Options = { profile?: string; @@ -35,22 +36,32 @@ const commandModule: CommandModule = { const contractNames = getExistingContracts(forgeSourceDir).map(({ basename }) => basename); const resolvedWorldConfig = resolveWorldConfig(config, contractNames); - const systems = Object.keys(resolvedWorldConfig.systems).map((systemName) => { - const contractData = getContractData(`${systemName}.sol`, systemName, outDir); + const systems = Object.keys(resolvedWorldConfig.systems).map((name) => { + const contractData = getContractData(`${name}.sol`, name, outDir); return { - systemName, + name, bytecode: contractData.bytecode, }; }); - console.log(systems); + const modules = config.modules.map((mod) => { + const contractData = + defaultModuleContracts.find((defaultMod) => defaultMod.name === mod.name) ?? + getContractData(`${mod.name}.sol`, mod.name, outDir); + + return { + name: mod.name, + bytecode: contractData.bytecode, + }; + }); // Wrap in try/catch, because yargs seems to swallow errors try { await verify({ foundryProfile: profile, systems, + modules, }); } catch (error) { logError(error); diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index e86768347e..3b63e9bd2d 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -13,7 +13,8 @@ import worldFactoryBuild from "@latticexyz/world/out/WorldFactory.sol/WorldFacto type VerifyOptions = { foundryProfile?: string; - systems: { systemName: string; bytecode: Hex }[]; + systems: { name: string; bytecode: Hex }[]; + modules: { name: string; bytecode: Hex }[]; }; // The contracts that are deployed in ensureWorldFactory @@ -34,7 +35,11 @@ async function verifyContract(foundryProfile: string | undefined, deployerAddres }); } -export async function verify({ foundryProfile = process.env.FOUNDRY_PROFILE, systems }: VerifyOptions): Promise { +export async function verify({ + foundryProfile = process.env.FOUNDRY_PROFILE, + systems, + modules, +}: VerifyOptions): Promise { const privateKey = process.env.PRIVATE_KEY as Hex; if (!privateKey) { throw new MUDError( @@ -54,8 +59,13 @@ in your contracts directory to use the default anvil private key.`, const deployerAddress = await ensureDeployer(client); await Promise.all( - systems.map(({ systemName, bytecode }) => verifyContract(foundryProfile, deployerAddress, systemName, bytecode)), + systems.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), ); + // TODO: fetch these from world-modules + await Promise.all( + modules.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), + ); + // TODO: fetch these from world await Promise.all( WORLD_FACTORY.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), ); From 0974aa472ca2ccbe1f29cf71ba146a56d31c87d8 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Tue, 16 Apr 2024 12:46:07 +0100 Subject: [PATCH 10/62] feat: use cwd --- packages/cli/src/verify.ts | 23 +++++++++++++++++++---- packages/common/src/foundry/index.ts | 3 ++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 3b63e9bd2d..75887c149b 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -35,6 +35,20 @@ async function verifyContract(foundryProfile: string | undefined, deployerAddres }); } +async function verifyContractWorld( + foundryProfile: string | undefined, + deployerAddress: Hex, + name: string, + bytecode: Hex, +) { + const system = getCreate2Address({ from: deployerAddress, bytecode, salt }); + + await forge(["verify-contract", system, name, "--verifier", "sourcify"], { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }); +} + export async function verify({ foundryProfile = process.env.FOUNDRY_PROFILE, systems, @@ -61,12 +75,13 @@ in your contracts directory to use the default anvil private key.`, await Promise.all( systems.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), ); - // TODO: fetch these from world-modules + + // TODO: fetch these from world await Promise.all( - modules.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), + WORLD_FACTORY.map(({ name, bytecode }) => verifyContractWorld(foundryProfile, deployerAddress, name, bytecode)), ); - // TODO: fetch these from world + // TODO: fetch these from world-modules await Promise.all( - WORLD_FACTORY.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), + modules.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), ); } diff --git a/packages/common/src/foundry/index.ts b/packages/common/src/foundry/index.ts index 83f20bff42..628a98deea 100644 --- a/packages/common/src/foundry/index.ts +++ b/packages/common/src/foundry/index.ts @@ -87,12 +87,13 @@ export async function getRemappings(profile?: string): Promise<[string, string][ */ export async function forge( args: string[], - options?: { profile?: string; silent?: boolean; env?: NodeJS.ProcessEnv }, + options?: { profile?: string; silent?: boolean; env?: NodeJS.ProcessEnv; cwd?: string }, ): Promise { const execOptions: Options = { env: { FOUNDRY_PROFILE: options?.profile, ...options?.env }, stdout: "inherit", stderr: "pipe", + cwd: options?.cwd, }; await (options?.silent ? execa("forge", args, execOptions) : execLog("forge", args, execOptions)); From 663b7385b2502adbe0ac7b153d90b7adb1236932 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Tue, 16 Apr 2024 16:48:55 +0100 Subject: [PATCH 11/62] chore: remove old rpc --- examples/minimal/packages/contracts/foundry.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/minimal/packages/contracts/foundry.toml b/examples/minimal/packages/contracts/foundry.toml index 3580e62ef6..22fd64d7d9 100644 --- a/examples/minimal/packages/contracts/foundry.toml +++ b/examples/minimal/packages/contracts/foundry.toml @@ -24,5 +24,4 @@ fs_permissions = [{ access = "read", path = "./"}] eth_rpc_url = "https://follower.testnet-chain.linfra.xyz" [profile.holesky] -eth_rpc_url = "https://17000.rpc.thirdweb.com" -# eth_rpc_url = "https://ethereum-holesky.publicnode.com" +eth_rpc_url = "https://ethereum-holesky.publicnode.com" From 38bbb1c75a44c9710916e5e3b53f0202245bf7dc Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Tue, 16 Apr 2024 17:37:14 +0100 Subject: [PATCH 12/62] chore: changeset --- .changeset/many-bulldogs-pay.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/many-bulldogs-pay.md diff --git a/.changeset/many-bulldogs-pay.md b/.changeset/many-bulldogs-pay.md new file mode 100644 index 0000000000..8a3bf24eb2 --- /dev/null +++ b/.changeset/many-bulldogs-pay.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/cli": patch +--- + +Added a new `mud verify` command which verifies all contracts in a project. This includes systems, modules, the WorldFactory and World. From 255add6b9353900ced9461150fde73769d408e98 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 12:13:11 +0100 Subject: [PATCH 13/62] refactor: no worldAddress --- packages/cli/src/verify.ts | 44 +++++++++++--------------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 75887c149b..6dfc905a6b 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -4,12 +4,7 @@ import { salt } from "./deploy/common"; import { ensureDeployer } from "./deploy/ensureDeployer"; import { privateKeyToAccount } from "viem/accounts"; import { MUDError } from "@latticexyz/common/errors"; -import accessManagementSystemBuild from "@latticexyz/world/out/AccessManagementSystem.sol/AccessManagementSystem.json" assert { type: "json" }; -import balanceTransferSystemBuild from "@latticexyz/world/out/BalanceTransferSystem.sol/BalanceTransferSystem.json" assert { type: "json" }; -import batchCallSystemBuild from "@latticexyz/world/out/BatchCallSystem.sol/BatchCallSystem.json" assert { type: "json" }; -import registrationSystemBuild from "@latticexyz/world/out/RegistrationSystem.sol/RegistrationSystem.json" assert { type: "json" }; -import initModuleBuild from "@latticexyz/world/out/InitModule.sol/InitModule.json" assert { type: "json" }; -import worldFactoryBuild from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.json" assert { type: "json" }; +import { getWorldFactoryContracts } from "./deploy/ensureWorldFactory"; type VerifyOptions = { foundryProfile?: string; @@ -17,35 +12,18 @@ type VerifyOptions = { modules: { name: string; bytecode: Hex }[]; }; -// The contracts that are deployed in ensureWorldFactory -const WORLD_FACTORY = [ - { name: "AccessManagementSystem", bytecode: accessManagementSystemBuild.bytecode.object as Hex }, - { name: "BalanceTransferSystem", bytecode: balanceTransferSystemBuild.bytecode.object as Hex }, - { name: "BatchCallSystem", bytecode: batchCallSystemBuild.bytecode.object as Hex }, - { name: "RegistrationSystem", bytecode: registrationSystemBuild.bytecode.object as Hex }, - { name: "InitModule", bytecode: initModuleBuild.bytecode.object as Hex }, - { name: "WorldFactory", bytecode: worldFactoryBuild.bytecode.object as Hex }, -]; - -async function verifyContract(foundryProfile: string | undefined, deployerAddress: Hex, name: string, bytecode: Hex) { - const system = getCreate2Address({ from: deployerAddress, bytecode, salt }); - - await forge(["verify-contract", system, name, "--verifier", "sourcify"], { - profile: foundryProfile, - }); -} - -async function verifyContractWorld( +async function verifyContract( foundryProfile: string | undefined, deployerAddress: Hex, name: string, bytecode: Hex, + cwd?: string, ) { const system = getCreate2Address({ from: deployerAddress, bytecode, salt }); - await forge(["verify-contract", system, name, "--verifier", "sourcify"], { + await forge(["verify-contract", system, name, "--verifier", "sourcify", "--chain", "holesky"], { profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", + cwd, }); } @@ -76,12 +54,16 @@ in your contracts directory to use the default anvil private key.`, systems.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), ); - // TODO: fetch these from world await Promise.all( - WORLD_FACTORY.map(({ name, bytecode }) => verifyContractWorld(foundryProfile, deployerAddress, name, bytecode)), + getWorldFactoryContracts(deployerAddress).map(({ label, bytecode }) => { + if (label) { + verifyContract(foundryProfile, deployerAddress, label, bytecode, "node_modules/@latticexyz/world"); + } + }), ); - // TODO: fetch these from world-modules await Promise.all( - modules.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), + modules.map(({ name, bytecode }) => + verifyContract(foundryProfile, deployerAddress, name, bytecode, "node_modules/@latticexyz/world-modules"), + ), ); } From 41783a5501432bcd5774f053552da80f62c7c7c3 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 12:41:39 +0100 Subject: [PATCH 14/62] refactor: get world factory contracts --- packages/cli/src/commands/verify.ts | 7 +- packages/cli/src/deploy/ensureWorldFactory.ts | 68 +++++++++++++++---- packages/cli/src/verify.ts | 19 ++++-- 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index da1ab5fc6f..98e21a3138 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -21,7 +21,6 @@ const commandModule: CommandModule = { builder(yargs) { return yargs.options({ profile: { type: "string", desc: "The foundry profile to use" }, - worldAddress: { type: "string", desc: "Deploy to an existing World at the given address" }, }); }, @@ -40,8 +39,9 @@ const commandModule: CommandModule = { const contractData = getContractData(`${name}.sol`, name, outDir); return { - name, + label: name, bytecode: contractData.bytecode, + deployedBytecodeSize: contractData.deployedBytecodeSize, }; }); @@ -51,8 +51,9 @@ const commandModule: CommandModule = { getContractData(`${mod.name}.sol`, mod.name, outDir); return { - name: mod.name, + label: mod.name, bytecode: contractData.bytecode, + deployedBytecodeSize: contractData.deployedBytecodeSize, }; }); diff --git a/packages/cli/src/deploy/ensureWorldFactory.ts b/packages/cli/src/deploy/ensureWorldFactory.ts index 0c241f7669..5d31f54c5f 100644 --- a/packages/cli/src/deploy/ensureWorldFactory.ts +++ b/packages/cli/src/deploy/ensureWorldFactory.ts @@ -11,10 +11,7 @@ import { salt } from "./common"; import { ensureContractsDeployed } from "./ensureContractsDeployed"; import { Contract } from "./ensureContract"; -export async function ensureWorldFactory( - client: Client, - deployerAddress: Hex, -): Promise
{ +export function getWorldFactoryContracts(deployerAddress: Hex): readonly Contract[] { const accessManagementSystemDeployedBytecodeSize = size(accessManagementSystemBuild.deployedBytecode.object as Hex); const accessManagementSystemBytecode = accessManagementSystemBuild.bytecode.object as Hex; const accessManagementSystem = getCreate2Address({ @@ -59,40 +56,85 @@ export async function ensureWorldFactory( args: [initModule], }); - const worldFactory = getCreate2Address({ from: deployerAddress, bytecode: worldFactoryBytecode, salt }); - - const worldFactoryContracts: readonly Contract[] = [ + return [ { bytecode: accessManagementSystemBytecode, deployedBytecodeSize: accessManagementSystemDeployedBytecodeSize, - label: "access management system", + label: "AccessManagementSystem", }, { bytecode: balanceTransferSystemBytecode, deployedBytecodeSize: balanceTransferSystemDeployedBytecodeSize, - label: "balance transfer system", + label: "BalanceTransferSystem", }, { bytecode: batchCallSystemBytecode, deployedBytecodeSize: batchCallSystemDeployedBytecodeSize, - label: "batch call system", + label: "BatchCallSystem", }, { bytecode: registrationBytecode, deployedBytecodeSize: registrationDeployedBytecodeSize, - label: "core registration system", + label: "RegistrationSystem", }, { bytecode: initModuleBytecode, deployedBytecodeSize: initModuleDeployedBytecodeSize, - label: "core module", + label: "InitModule", }, { bytecode: worldFactoryBytecode, deployedBytecodeSize: worldFactoryDeployedBytecodeSize, - label: "world factory", + label: "WorldFactory", }, ]; +} + +export async function ensureWorldFactory( + client: Client, + deployerAddress: Hex, +): Promise
{ + const accessManagementSystemBytecode = accessManagementSystemBuild.bytecode.object as Hex; + const accessManagementSystem = getCreate2Address({ + from: deployerAddress, + bytecode: accessManagementSystemBytecode, + salt, + }); + + const balanceTransferSystemBytecode = balanceTransferSystemBuild.bytecode.object as Hex; + const balanceTransferSystem = getCreate2Address({ + from: deployerAddress, + bytecode: balanceTransferSystemBytecode, + salt, + }); + + const batchCallSystemBytecode = batchCallSystemBuild.bytecode.object as Hex; + const batchCallSystem = getCreate2Address({ from: deployerAddress, bytecode: batchCallSystemBytecode, salt }); + + const registrationBytecode = registrationSystemBuild.bytecode.object as Hex; + const registration = getCreate2Address({ + from: deployerAddress, + bytecode: registrationBytecode, + salt, + }); + + const initModuleBytecode = encodeDeployData({ + bytecode: initModuleBuild.bytecode.object as Hex, + abi: initModuleAbi, + args: [accessManagementSystem, balanceTransferSystem, batchCallSystem, registration], + }); + + const initModule = getCreate2Address({ from: deployerAddress, bytecode: initModuleBytecode, salt }); + + const worldFactoryBytecode = encodeDeployData({ + bytecode: worldFactoryBuild.bytecode.object as Hex, + abi: worldFactoryAbi, + args: [initModule], + }); + + const worldFactory = getCreate2Address({ from: deployerAddress, bytecode: worldFactoryBytecode, salt }); + + const worldFactoryContracts = getWorldFactoryContracts(deployerAddress); // WorldFactory constructor doesn't call InitModule, only sets its address, so we can do these in parallel since the address is deterministic await ensureContractsDeployed({ diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 6dfc905a6b..4c5c0d8668 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -5,11 +5,12 @@ import { ensureDeployer } from "./deploy/ensureDeployer"; import { privateKeyToAccount } from "viem/accounts"; import { MUDError } from "@latticexyz/common/errors"; import { getWorldFactoryContracts } from "./deploy/ensureWorldFactory"; +import { Contract } from "./deploy/ensureContract"; type VerifyOptions = { foundryProfile?: string; - systems: { name: string; bytecode: Hex }[]; - modules: { name: string; bytecode: Hex }[]; + systems: Contract[]; + modules: Contract[]; }; async function verifyContract( @@ -51,7 +52,11 @@ in your contracts directory to use the default anvil private key.`, const deployerAddress = await ensureDeployer(client); await Promise.all( - systems.map(({ name, bytecode }) => verifyContract(foundryProfile, deployerAddress, name, bytecode)), + systems.map(({ label, bytecode }) => { + if (label) { + verifyContract(foundryProfile, deployerAddress, label, bytecode); + } + }), ); await Promise.all( @@ -62,8 +67,10 @@ in your contracts directory to use the default anvil private key.`, }), ); await Promise.all( - modules.map(({ name, bytecode }) => - verifyContract(foundryProfile, deployerAddress, name, bytecode, "node_modules/@latticexyz/world-modules"), - ), + modules.map(({ label, bytecode }) => { + if (label) { + verifyContract(foundryProfile, deployerAddress, label, bytecode, "node_modules/@latticexyz/world-modules"); + } + }), ); } From f48f29c55118477d879787f468e79b6ead8b987d Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 16:51:27 +0100 Subject: [PATCH 15/62] refactor: contract --- packages/cli/src/verify.ts | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 4c5c0d8668..aaa9f54e45 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -16,13 +16,16 @@ type VerifyOptions = { async function verifyContract( foundryProfile: string | undefined, deployerAddress: Hex, - name: string, - bytecode: Hex, + contract: Contract, cwd?: string, ) { - const system = getCreate2Address({ from: deployerAddress, bytecode, salt }); + if (!contract.label) { + throw new MUDError("Need a label"); + } + + const system = getCreate2Address({ from: deployerAddress, bytecode: contract.bytecode, salt }); - await forge(["verify-contract", system, name, "--verifier", "sourcify", "--chain", "holesky"], { + await forge(["verify-contract", system, contract.label, "--verifier", "sourcify", "--chain", "holesky"], { profile: foundryProfile, cwd, }); @@ -52,25 +55,20 @@ in your contracts directory to use the default anvil private key.`, const deployerAddress = await ensureDeployer(client); await Promise.all( - systems.map(({ label, bytecode }) => { - if (label) { - verifyContract(foundryProfile, deployerAddress, label, bytecode); - } + systems.map((contract) => { + verifyContract(foundryProfile, deployerAddress, contract); }), ); await Promise.all( - getWorldFactoryContracts(deployerAddress).map(({ label, bytecode }) => { - if (label) { - verifyContract(foundryProfile, deployerAddress, label, bytecode, "node_modules/@latticexyz/world"); - } + getWorldFactoryContracts(deployerAddress).map((contract) => { + verifyContract(foundryProfile, deployerAddress, contract, "node_modules/@latticexyz/world"); }), ); + await Promise.all( - modules.map(({ label, bytecode }) => { - if (label) { - verifyContract(foundryProfile, deployerAddress, label, bytecode, "node_modules/@latticexyz/world-modules"); - } + modules.map((contract) => { + verifyContract(foundryProfile, deployerAddress, contract, "node_modules/@latticexyz/world-modules"); }), ); } From d63a0673a3f83577c19024ca8a5d80191419ace1 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 17:08:20 +0100 Subject: [PATCH 16/62] fix: brackets, options --- packages/cli/src/commands/verify.ts | 17 +++++++++++------ packages/cli/src/verify.ts | 18 +++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 98e21a3138..97a9aac17f 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -10,7 +10,9 @@ import { getContractData } from "../utils/getContractData"; import { defaultModuleContracts } from "../utils/defaultModuleContracts"; type Options = { + configPath?: string; profile?: string; + srcDir?: string; }; const commandModule: CommandModule = { @@ -20,21 +22,24 @@ const commandModule: CommandModule = { builder(yargs) { return yargs.options({ + configPath: { type: "string", desc: "Path to the config file" }, profile: { type: "string", desc: "The foundry profile to use" }, + srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." }, }); }, - async handler({ profile }) { - const configV2 = (await loadConfig(undefined)) as WorldConfig; + async handler(opts) { + const profile = opts.profile ?? process.env.FOUNDRY_PROFILE; + + const configV2 = (await loadConfig(opts.configPath)) as WorldConfig; const config = worldToV1(configV2); - const srcDir = await getSrcDirectory(profile); + const srcDir = opts.srcDir ?? (await getSrcDirectory(profile)); const outDir = await getOutDirectory(profile); - const forgeSourceDir = srcDir; - const contractNames = getExistingContracts(forgeSourceDir).map(({ basename }) => basename); - + const contractNames = getExistingContracts(srcDir).map(({ basename }) => basename); const resolvedWorldConfig = resolveWorldConfig(config, contractNames); + const systems = Object.keys(resolvedWorldConfig.systems).map((name) => { const contractData = getContractData(`${name}.sol`, name, outDir); diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index aaa9f54e45..69e73d9d1d 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -54,21 +54,17 @@ in your contracts directory to use the default anvil private key.`, const deployerAddress = await ensureDeployer(client); - await Promise.all( - systems.map((contract) => { - verifyContract(foundryProfile, deployerAddress, contract); - }), - ); + await Promise.all(systems.map((contract) => verifyContract(foundryProfile, deployerAddress, contract))); await Promise.all( - getWorldFactoryContracts(deployerAddress).map((contract) => { - verifyContract(foundryProfile, deployerAddress, contract, "node_modules/@latticexyz/world"); - }), + getWorldFactoryContracts(deployerAddress).map((contract) => + verifyContract(foundryProfile, deployerAddress, contract, "node_modules/@latticexyz/world"), + ), ); await Promise.all( - modules.map((contract) => { - verifyContract(foundryProfile, deployerAddress, contract, "node_modules/@latticexyz/world-modules"); - }), + modules.map((contract) => + verifyContract(foundryProfile, deployerAddress, contract, "node_modules/@latticexyz/world-modules"), + ), ); } From 54196736369451bd7795cd4fd7de13ada29a9208 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 17:27:54 +0100 Subject: [PATCH 17/62] feat: verify world --- examples/minimal/packages/contracts/package.json | 2 +- packages/cli/src/commands/verify.ts | 4 ++++ packages/cli/src/verify.ts | 9 +++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/minimal/packages/contracts/package.json b/examples/minimal/packages/contracts/package.json index ea7cc7b821..550301089e 100644 --- a/examples/minimal/packages/contracts/package.json +++ b/examples/minimal/packages/contracts/package.json @@ -15,7 +15,7 @@ "prettier": "prettier --write 'src/**/*.sol'", "solhint": "solhint --config ./.solhint.json 'src/**/*.sol' --fix", "test": "mud test", - "verify": "pnpm mud verify --profile=holesky" + "verify": "pnpm mud verify --profile=holesky --worldAddress=0xcf6179d4c4ddc99ba29709d87c6bf9b0fefae0fc" }, "devDependencies": { "@latticexyz/cli": "link:../../../../packages/cli", diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 97a9aac17f..f76ac827d7 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -8,8 +8,10 @@ import { getOutDirectory, getSrcDirectory } from "@latticexyz/common/foundry"; import { getExistingContracts } from "../utils/getExistingContracts"; import { getContractData } from "../utils/getContractData"; import { defaultModuleContracts } from "../utils/defaultModuleContracts"; +import { Hex } from "viem"; type Options = { + worldAddress?: string; configPath?: string; profile?: string; srcDir?: string; @@ -24,6 +26,7 @@ const commandModule: CommandModule = { return yargs.options({ configPath: { type: "string", desc: "Path to the config file" }, profile: { type: "string", desc: "The foundry profile to use" }, + worldAddress: { type: "string", desc: "Deploy to an existing World at the given address" }, srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." }, }); }, @@ -68,6 +71,7 @@ const commandModule: CommandModule = { foundryProfile: profile, systems, modules, + worldAddress: opts.worldAddress ? (opts.worldAddress as Hex) : undefined, }); } catch (error) { logError(error); diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 69e73d9d1d..0aa2998761 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -11,6 +11,7 @@ type VerifyOptions = { foundryProfile?: string; systems: Contract[]; modules: Contract[]; + worldAddress?: Hex; }; async function verifyContract( @@ -35,6 +36,7 @@ export async function verify({ foundryProfile = process.env.FOUNDRY_PROFILE, systems, modules, + worldAddress, }: VerifyOptions): Promise { const privateKey = process.env.PRIVATE_KEY as Hex; if (!privateKey) { @@ -67,4 +69,11 @@ in your contracts directory to use the default anvil private key.`, verifyContract(foundryProfile, deployerAddress, contract, "node_modules/@latticexyz/world-modules"), ), ); + + if (worldAddress) { + await forge(["verify-contract", worldAddress, "World", "--verifier", "sourcify", "--chain", "holesky"], { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }); + } } From 1bd2885805cc823f3b79b8549cbe30df887378e6 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 17:32:43 +0100 Subject: [PATCH 18/62] refactor: rpc url --- packages/cli/src/verify.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 0aa2998761..148e4280ce 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -18,6 +18,7 @@ async function verifyContract( foundryProfile: string | undefined, deployerAddress: Hex, contract: Contract, + rpc: string, cwd?: string, ) { if (!contract.label) { @@ -26,7 +27,7 @@ async function verifyContract( const system = getCreate2Address({ from: deployerAddress, bytecode: contract.bytecode, salt }); - await forge(["verify-contract", system, contract.label, "--verifier", "sourcify", "--chain", "holesky"], { + await forge(["verify-contract", system, contract.label, "--verifier", "sourcify", "--rpc-url", rpc], { profile: foundryProfile, cwd, }); @@ -56,22 +57,22 @@ in your contracts directory to use the default anvil private key.`, const deployerAddress = await ensureDeployer(client); - await Promise.all(systems.map((contract) => verifyContract(foundryProfile, deployerAddress, contract))); + await Promise.all(systems.map((contract) => verifyContract(foundryProfile, deployerAddress, contract, rpc))); await Promise.all( getWorldFactoryContracts(deployerAddress).map((contract) => - verifyContract(foundryProfile, deployerAddress, contract, "node_modules/@latticexyz/world"), + verifyContract(foundryProfile, deployerAddress, contract, rpc, "node_modules/@latticexyz/world"), ), ); await Promise.all( modules.map((contract) => - verifyContract(foundryProfile, deployerAddress, contract, "node_modules/@latticexyz/world-modules"), + verifyContract(foundryProfile, deployerAddress, contract, rpc, "node_modules/@latticexyz/world-modules"), ), ); if (worldAddress) { - await forge(["verify-contract", worldAddress, "World", "--verifier", "sourcify", "--chain", "holesky"], { + await forge(["verify-contract", worldAddress, "World", "--verifier", "sourcify", "--rpc-url", rpc], { profile: foundryProfile, cwd: "node_modules/@latticexyz/world", }); From 005dcc795c7e7b097db08e679e7774b5ea75c6c4 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 17:35:13 +0100 Subject: [PATCH 19/62] worlds.json --- examples/minimal/packages/contracts/worlds.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/minimal/packages/contracts/worlds.json b/examples/minimal/packages/contracts/worlds.json index 3e7ec7daf5..2d47ae4158 100644 --- a/examples/minimal/packages/contracts/worlds.json +++ b/examples/minimal/packages/contracts/worlds.json @@ -3,11 +3,7 @@ "address": "0xb51cE08442de2aB60f327566db833eed15B47b60", "blockNumber": 21817970 }, - "17000": { - "address": "0xb1eca382fe27df86db5fce82830fbd3cb942f05b", - "blockNumber": 1352275 - }, "31337": { - "address": "0x8ac4e60625d49ab7ab0055c598dd62754e71a089" + "address": "0x6e9474e9c83676b9a71133ff96db43e7aa0a4342" } } \ No newline at end of file From 436242fcc097ca5517946b204eeed3e26775102d Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 19:00:48 +0100 Subject: [PATCH 20/62] docs: worldaddress --- packages/cli/src/commands/verify.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index f76ac827d7..8cfec14b35 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -26,7 +26,7 @@ const commandModule: CommandModule = { return yargs.options({ configPath: { type: "string", desc: "Path to the config file" }, profile: { type: "string", desc: "The foundry profile to use" }, - worldAddress: { type: "string", desc: "Deploy to an existing World at the given address" }, + worldAddress: { type: "string", desc: "Verify an existing World at the given address" }, srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." }, }); }, From ebe5775e2318f60aedcee0133b9b63fa2d60fb85 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 19:26:19 +0100 Subject: [PATCH 21/62] refactor: hardcoded deployer --- packages/cli/src/deploy/ensureDeployer.ts | 2 +- packages/cli/src/verify.ts | 29 +++++------------------ 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/packages/cli/src/deploy/ensureDeployer.ts b/packages/cli/src/deploy/ensureDeployer.ts index 92c7c136b0..d5fd7383ee 100644 --- a/packages/cli/src/deploy/ensureDeployer.ts +++ b/packages/cli/src/deploy/ensureDeployer.ts @@ -3,7 +3,7 @@ import { getBalance, getBytecode, sendRawTransaction, sendTransaction, waitForTr import deployment from "./create2/deployment.json"; import { debug } from "./debug"; -const deployer = `0x${deployment.address}` as const; +export const deployer = `0x${deployment.address}` as const; const deployerBytecode = `0x${deployment.bytecode}` as const; export async function ensureDeployer(client: Client): Promise
{ diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 148e4280ce..cb03f5ece8 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,8 +1,7 @@ import { forge, getRpcUrl } from "@latticexyz/common/foundry"; -import { Hex, createWalletClient, getCreate2Address, http } from "viem"; +import { Hex, getCreate2Address } from "viem"; import { salt } from "./deploy/common"; -import { ensureDeployer } from "./deploy/ensureDeployer"; -import { privateKeyToAccount } from "viem/accounts"; +import { deployer } from "./deploy/ensureDeployer"; import { MUDError } from "@latticexyz/common/errors"; import { getWorldFactoryContracts } from "./deploy/ensureWorldFactory"; import { Contract } from "./deploy/ensureContract"; @@ -39,35 +38,19 @@ export async function verify({ modules, worldAddress, }: VerifyOptions): Promise { - const privateKey = process.env.PRIVATE_KEY as Hex; - if (!privateKey) { - throw new MUDError( - `Missing PRIVATE_KEY environment variable. -Run 'echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env' -in your contracts directory to use the default anvil private key.`, - ); - } - const rpc = await getRpcUrl(foundryProfile); - const client = createWalletClient({ - transport: http(rpc), - account: privateKeyToAccount(privateKey), - }); - - const deployerAddress = await ensureDeployer(client); - - await Promise.all(systems.map((contract) => verifyContract(foundryProfile, deployerAddress, contract, rpc))); + await Promise.all(systems.map((contract) => verifyContract(foundryProfile, deployer, contract, rpc))); await Promise.all( - getWorldFactoryContracts(deployerAddress).map((contract) => - verifyContract(foundryProfile, deployerAddress, contract, rpc, "node_modules/@latticexyz/world"), + getWorldFactoryContracts(deployer).map((contract) => + verifyContract(foundryProfile, deployer, contract, rpc, "node_modules/@latticexyz/world"), ), ); await Promise.all( modules.map((contract) => - verifyContract(foundryProfile, deployerAddress, contract, rpc, "node_modules/@latticexyz/world-modules"), + verifyContract(foundryProfile, deployer, contract, rpc, "node_modules/@latticexyz/world-modules"), ), ); From 05dd33a1282a974dd6f81b57f860f3c03c4b5a45 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 19:31:34 +0100 Subject: [PATCH 22/62] refactor: require worldaddress --- packages/cli/src/commands/verify.ts | 7 ++++++- packages/cli/src/verify.ts | 12 +++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 8cfec14b35..df61bb35ea 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -9,6 +9,7 @@ import { getExistingContracts } from "../utils/getExistingContracts"; import { getContractData } from "../utils/getContractData"; import { defaultModuleContracts } from "../utils/defaultModuleContracts"; import { Hex } from "viem"; +import { MUDError } from "@latticexyz/common/errors"; type Options = { worldAddress?: string; @@ -32,6 +33,10 @@ const commandModule: CommandModule = { }, async handler(opts) { + if (!opts.worldAddress) { + throw new MUDError("Need a world address"); + } + const profile = opts.profile ?? process.env.FOUNDRY_PROFILE; const configV2 = (await loadConfig(opts.configPath)) as WorldConfig; @@ -71,7 +76,7 @@ const commandModule: CommandModule = { foundryProfile: profile, systems, modules, - worldAddress: opts.worldAddress ? (opts.worldAddress as Hex) : undefined, + worldAddress: opts.worldAddress as Hex, }); } catch (error) { logError(error); diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index cb03f5ece8..48aa3fc0a7 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -10,7 +10,7 @@ type VerifyOptions = { foundryProfile?: string; systems: Contract[]; modules: Contract[]; - worldAddress?: Hex; + worldAddress: Hex; }; async function verifyContract( @@ -54,10 +54,8 @@ export async function verify({ ), ); - if (worldAddress) { - await forge(["verify-contract", worldAddress, "World", "--verifier", "sourcify", "--rpc-url", rpc], { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }); - } + await forge(["verify-contract", worldAddress, "World", "--verifier", "sourcify", "--rpc-url", rpc], { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }); } From 7edceaf04e587eda780e7db2691ce7c7f2ccf3f1 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 19:46:56 +0100 Subject: [PATCH 23/62] feat: verifier --- .../minimal/packages/contracts/package.json | 2 +- packages/cli/src/commands/verify.ts | 3 ++ packages/cli/src/verify.ts | 42 +++++++++++++------ 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/examples/minimal/packages/contracts/package.json b/examples/minimal/packages/contracts/package.json index 550301089e..f37210808d 100644 --- a/examples/minimal/packages/contracts/package.json +++ b/examples/minimal/packages/contracts/package.json @@ -15,7 +15,7 @@ "prettier": "prettier --write 'src/**/*.sol'", "solhint": "solhint --config ./.solhint.json 'src/**/*.sol' --fix", "test": "mud test", - "verify": "pnpm mud verify --profile=holesky --worldAddress=0xcf6179d4c4ddc99ba29709d87c6bf9b0fefae0fc" + "verify": "pnpm mud verify --profile=holesky --worldAddress=0xcf6179d4c4ddc99ba29709d87c6bf9b0fefae0fc --verifier sourcify" }, "devDependencies": { "@latticexyz/cli": "link:../../../../packages/cli", diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index df61bb35ea..5dcd4aaaeb 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -16,6 +16,7 @@ type Options = { configPath?: string; profile?: string; srcDir?: string; + verifier?: string; }; const commandModule: CommandModule = { @@ -29,6 +30,7 @@ const commandModule: CommandModule = { profile: { type: "string", desc: "The foundry profile to use" }, worldAddress: { type: "string", desc: "Verify an existing World at the given address" }, srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." }, + verifier: { type: "string", desc: "The verifier to use" }, }); }, @@ -77,6 +79,7 @@ const commandModule: CommandModule = { systems, modules, worldAddress: opts.worldAddress as Hex, + verifier: opts.verifier, }); } catch (error) { logError(error); diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 48aa3fc0a7..a5547782d9 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -8,16 +8,39 @@ import { Contract } from "./deploy/ensureContract"; type VerifyOptions = { foundryProfile?: string; + verifier?: string; systems: Contract[]; modules: Contract[]; worldAddress: Hex; }; +async function verifyContractUnderlying( + system: Hex, + label: string, + rpc: string, + foundryProfile?: string, + cwd?: string, + verifier?: string, +) { + if (verifier) { + await forge(["verify-contract", system, label, "--rpc-url", rpc, "--verifier", verifier], { + profile: foundryProfile, + cwd, + }); + } else { + await forge(["verify-contract", system, label, "--rpc-url", rpc], { + profile: foundryProfile, + cwd, + }); + } +} + async function verifyContract( - foundryProfile: string | undefined, deployerAddress: Hex, contract: Contract, rpc: string, + verifier?: string, + foundryProfile?: string, cwd?: string, ) { if (!contract.label) { @@ -26,10 +49,7 @@ async function verifyContract( const system = getCreate2Address({ from: deployerAddress, bytecode: contract.bytecode, salt }); - await forge(["verify-contract", system, contract.label, "--verifier", "sourcify", "--rpc-url", rpc], { - profile: foundryProfile, - cwd, - }); + return verifyContractUnderlying(system, contract.label, rpc, foundryProfile, cwd, verifier); } export async function verify({ @@ -37,25 +57,23 @@ export async function verify({ systems, modules, worldAddress, + verifier, }: VerifyOptions): Promise { const rpc = await getRpcUrl(foundryProfile); - await Promise.all(systems.map((contract) => verifyContract(foundryProfile, deployer, contract, rpc))); + await Promise.all(systems.map((contract) => verifyContract(deployer, contract, rpc, verifier, foundryProfile))); await Promise.all( getWorldFactoryContracts(deployer).map((contract) => - verifyContract(foundryProfile, deployer, contract, rpc, "node_modules/@latticexyz/world"), + verifyContract(deployer, contract, rpc, verifier, foundryProfile, "node_modules/@latticexyz/world"), ), ); await Promise.all( modules.map((contract) => - verifyContract(foundryProfile, deployer, contract, rpc, "node_modules/@latticexyz/world-modules"), + verifyContract(deployer, contract, rpc, verifier, foundryProfile, "node_modules/@latticexyz/world-modules"), ), ); - await forge(["verify-contract", worldAddress, "World", "--verifier", "sourcify", "--rpc-url", rpc], { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }); + verifyContractUnderlying(worldAddress, "World", rpc, verifier, "node_modules/@latticexyz/world"); } From f2b7b3c87944bbbe5b345a1feed3c3eba67d22fc Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 19:48:48 +0100 Subject: [PATCH 24/62] refactor: names --- packages/cli/src/verify.ts | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index a5547782d9..055cab74a1 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -14,28 +14,28 @@ type VerifyOptions = { worldAddress: Hex; }; -async function verifyContractUnderlying( - system: Hex, +async function verifyContract( + address: Hex, label: string, rpc: string, + verifier?: string, foundryProfile?: string, cwd?: string, - verifier?: string, ) { if (verifier) { - await forge(["verify-contract", system, label, "--rpc-url", rpc, "--verifier", verifier], { + await forge(["verify-contract", address, label, "--rpc-url", rpc, "--verifier", verifier], { profile: foundryProfile, cwd, }); } else { - await forge(["verify-contract", system, label, "--rpc-url", rpc], { + await forge(["verify-contract", address, label, "--rpc-url", rpc], { profile: foundryProfile, cwd, }); } } -async function verifyContract( +async function verifyContractFromBytecode( deployerAddress: Hex, contract: Contract, rpc: string, @@ -47,9 +47,9 @@ async function verifyContract( throw new MUDError("Need a label"); } - const system = getCreate2Address({ from: deployerAddress, bytecode: contract.bytecode, salt }); + const address = getCreate2Address({ from: deployerAddress, bytecode: contract.bytecode, salt }); - return verifyContractUnderlying(system, contract.label, rpc, foundryProfile, cwd, verifier); + return verifyContract(address, contract.label, rpc, verifier, foundryProfile, cwd); } export async function verify({ @@ -61,19 +61,28 @@ export async function verify({ }: VerifyOptions): Promise { const rpc = await getRpcUrl(foundryProfile); - await Promise.all(systems.map((contract) => verifyContract(deployer, contract, rpc, verifier, foundryProfile))); + await Promise.all( + systems.map((contract) => verifyContractFromBytecode(deployer, contract, rpc, verifier, foundryProfile)), + ); await Promise.all( getWorldFactoryContracts(deployer).map((contract) => - verifyContract(deployer, contract, rpc, verifier, foundryProfile, "node_modules/@latticexyz/world"), + verifyContractFromBytecode(deployer, contract, rpc, verifier, foundryProfile, "node_modules/@latticexyz/world"), ), ); await Promise.all( modules.map((contract) => - verifyContract(deployer, contract, rpc, verifier, foundryProfile, "node_modules/@latticexyz/world-modules"), + verifyContractFromBytecode( + deployer, + contract, + rpc, + verifier, + foundryProfile, + "node_modules/@latticexyz/world-modules", + ), ), ); - verifyContractUnderlying(worldAddress, "World", rpc, verifier, "node_modules/@latticexyz/world"); + verifyContract(worldAddress, "World", rpc, verifier, "node_modules/@latticexyz/world"); } From 503511ad88ff94a47e248acb7081d159b4ff4dce Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 19:55:33 +0100 Subject: [PATCH 25/62] refactor: getWorldFactoryContracts --- packages/cli/src/deploy/ensureWorldFactory.ts | 70 +++++-------------- packages/cli/src/verify.ts | 2 +- 2 files changed, 19 insertions(+), 53 deletions(-) diff --git a/packages/cli/src/deploy/ensureWorldFactory.ts b/packages/cli/src/deploy/ensureWorldFactory.ts index 5d31f54c5f..1be11de717 100644 --- a/packages/cli/src/deploy/ensureWorldFactory.ts +++ b/packages/cli/src/deploy/ensureWorldFactory.ts @@ -11,7 +11,7 @@ import { salt } from "./common"; import { ensureContractsDeployed } from "./ensureContractsDeployed"; import { Contract } from "./ensureContract"; -export function getWorldFactoryContracts(deployerAddress: Hex): readonly Contract[] { +export function getWorldFactoryContracts(deployerAddress: Hex): Record { const accessManagementSystemDeployedBytecodeSize = size(accessManagementSystemBuild.deployedBytecode.object as Hex); const accessManagementSystemBytecode = accessManagementSystemBuild.bytecode.object as Hex; const accessManagementSystem = getCreate2Address({ @@ -46,7 +46,6 @@ export function getWorldFactoryContracts(deployerAddress: Hex): readonly Contrac abi: initModuleAbi, args: [accessManagementSystem, balanceTransferSystem, batchCallSystem, registration], }); - const initModule = getCreate2Address({ from: deployerAddress, bytecode: initModuleBytecode, salt }); const worldFactoryDeployedBytecodeSize = size(worldFactoryBuild.deployedBytecode.object as Hex); @@ -55,93 +54,60 @@ export function getWorldFactoryContracts(deployerAddress: Hex): readonly Contrac abi: worldFactoryAbi, args: [initModule], }); + const worldFactory = getCreate2Address({ from: deployerAddress, bytecode: worldFactoryBytecode, salt }); - return [ - { + return { + AccessManagementSystem: { bytecode: accessManagementSystemBytecode, deployedBytecodeSize: accessManagementSystemDeployedBytecodeSize, label: "AccessManagementSystem", + address: accessManagementSystem, }, - { + BalanceTransferSystem: { bytecode: balanceTransferSystemBytecode, deployedBytecodeSize: balanceTransferSystemDeployedBytecodeSize, label: "BalanceTransferSystem", + address: balanceTransferSystem, }, - { + BatchCallSystem: { bytecode: batchCallSystemBytecode, deployedBytecodeSize: batchCallSystemDeployedBytecodeSize, label: "BatchCallSystem", + address: batchCallSystem, }, - { + RegistrationSystem: { bytecode: registrationBytecode, deployedBytecodeSize: registrationDeployedBytecodeSize, label: "RegistrationSystem", + address: registration, }, - { + InitModule: { bytecode: initModuleBytecode, deployedBytecodeSize: initModuleDeployedBytecodeSize, label: "InitModule", + address: initModule, }, - { + WorldFactory: { bytecode: worldFactoryBytecode, deployedBytecodeSize: worldFactoryDeployedBytecodeSize, label: "WorldFactory", + address: worldFactory, }, - ]; + }; } export async function ensureWorldFactory( client: Client, deployerAddress: Hex, ): Promise
{ - const accessManagementSystemBytecode = accessManagementSystemBuild.bytecode.object as Hex; - const accessManagementSystem = getCreate2Address({ - from: deployerAddress, - bytecode: accessManagementSystemBytecode, - salt, - }); - - const balanceTransferSystemBytecode = balanceTransferSystemBuild.bytecode.object as Hex; - const balanceTransferSystem = getCreate2Address({ - from: deployerAddress, - bytecode: balanceTransferSystemBytecode, - salt, - }); - - const batchCallSystemBytecode = batchCallSystemBuild.bytecode.object as Hex; - const batchCallSystem = getCreate2Address({ from: deployerAddress, bytecode: batchCallSystemBytecode, salt }); - - const registrationBytecode = registrationSystemBuild.bytecode.object as Hex; - const registration = getCreate2Address({ - from: deployerAddress, - bytecode: registrationBytecode, - salt, - }); - - const initModuleBytecode = encodeDeployData({ - bytecode: initModuleBuild.bytecode.object as Hex, - abi: initModuleAbi, - args: [accessManagementSystem, balanceTransferSystem, batchCallSystem, registration], - }); - - const initModule = getCreate2Address({ from: deployerAddress, bytecode: initModuleBytecode, salt }); - - const worldFactoryBytecode = encodeDeployData({ - bytecode: worldFactoryBuild.bytecode.object as Hex, - abi: worldFactoryAbi, - args: [initModule], - }); - - const worldFactory = getCreate2Address({ from: deployerAddress, bytecode: worldFactoryBytecode, salt }); - const worldFactoryContracts = getWorldFactoryContracts(deployerAddress); // WorldFactory constructor doesn't call InitModule, only sets its address, so we can do these in parallel since the address is deterministic await ensureContractsDeployed({ client, deployerAddress, - contracts: worldFactoryContracts, + contracts: Object.values(worldFactoryContracts), }); - return worldFactory; + return worldFactoryContracts["WorldFactory"].address; } diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 055cab74a1..f5c6e09ae6 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -66,7 +66,7 @@ export async function verify({ ); await Promise.all( - getWorldFactoryContracts(deployer).map((contract) => + Object.values(getWorldFactoryContracts(deployer)).map((contract) => verifyContractFromBytecode(deployer, contract, rpc, verifier, foundryProfile, "node_modules/@latticexyz/world"), ), ); From 3561ff320824067d4614cd45659689b2506a310a Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 19:56:56 +0100 Subject: [PATCH 26/62] refactor: seperate file --- packages/cli/src/deploy/ensureWorldFactory.ts | 98 +------------------ .../src/deploy/getWorldFactoryContracts.ts | 96 ++++++++++++++++++ packages/cli/src/verify.ts | 2 +- 3 files changed, 99 insertions(+), 97 deletions(-) create mode 100644 packages/cli/src/deploy/getWorldFactoryContracts.ts diff --git a/packages/cli/src/deploy/ensureWorldFactory.ts b/packages/cli/src/deploy/ensureWorldFactory.ts index 1be11de717..20c04e18f0 100644 --- a/packages/cli/src/deploy/ensureWorldFactory.ts +++ b/packages/cli/src/deploy/ensureWorldFactory.ts @@ -1,100 +1,6 @@ -import accessManagementSystemBuild from "@latticexyz/world/out/AccessManagementSystem.sol/AccessManagementSystem.json" assert { type: "json" }; -import balanceTransferSystemBuild from "@latticexyz/world/out/BalanceTransferSystem.sol/BalanceTransferSystem.json" assert { type: "json" }; -import batchCallSystemBuild from "@latticexyz/world/out/BatchCallSystem.sol/BatchCallSystem.json" assert { type: "json" }; -import registrationSystemBuild from "@latticexyz/world/out/RegistrationSystem.sol/RegistrationSystem.json" assert { type: "json" }; -import initModuleBuild from "@latticexyz/world/out/InitModule.sol/InitModule.json" assert { type: "json" }; -import initModuleAbi from "@latticexyz/world/out/InitModule.sol/InitModule.abi.json" assert { type: "json" }; -import worldFactoryBuild from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.json" assert { type: "json" }; -import worldFactoryAbi from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json" assert { type: "json" }; -import { Client, Transport, Chain, Account, Hex, getCreate2Address, encodeDeployData, size, Address } from "viem"; -import { salt } from "./common"; +import { Client, Transport, Chain, Account, Hex, Address } from "viem"; import { ensureContractsDeployed } from "./ensureContractsDeployed"; -import { Contract } from "./ensureContract"; - -export function getWorldFactoryContracts(deployerAddress: Hex): Record { - const accessManagementSystemDeployedBytecodeSize = size(accessManagementSystemBuild.deployedBytecode.object as Hex); - const accessManagementSystemBytecode = accessManagementSystemBuild.bytecode.object as Hex; - const accessManagementSystem = getCreate2Address({ - from: deployerAddress, - bytecode: accessManagementSystemBytecode, - salt, - }); - - const balanceTransferSystemDeployedBytecodeSize = size(balanceTransferSystemBuild.deployedBytecode.object as Hex); - const balanceTransferSystemBytecode = balanceTransferSystemBuild.bytecode.object as Hex; - const balanceTransferSystem = getCreate2Address({ - from: deployerAddress, - bytecode: balanceTransferSystemBytecode, - salt, - }); - - const batchCallSystemDeployedBytecodeSize = size(batchCallSystemBuild.deployedBytecode.object as Hex); - const batchCallSystemBytecode = batchCallSystemBuild.bytecode.object as Hex; - const batchCallSystem = getCreate2Address({ from: deployerAddress, bytecode: batchCallSystemBytecode, salt }); - - const registrationDeployedBytecodeSize = size(registrationSystemBuild.deployedBytecode.object as Hex); - const registrationBytecode = registrationSystemBuild.bytecode.object as Hex; - const registration = getCreate2Address({ - from: deployerAddress, - bytecode: registrationBytecode, - salt, - }); - - const initModuleDeployedBytecodeSize = size(initModuleBuild.deployedBytecode.object as Hex); - const initModuleBytecode = encodeDeployData({ - bytecode: initModuleBuild.bytecode.object as Hex, - abi: initModuleAbi, - args: [accessManagementSystem, balanceTransferSystem, batchCallSystem, registration], - }); - const initModule = getCreate2Address({ from: deployerAddress, bytecode: initModuleBytecode, salt }); - - const worldFactoryDeployedBytecodeSize = size(worldFactoryBuild.deployedBytecode.object as Hex); - const worldFactoryBytecode = encodeDeployData({ - bytecode: worldFactoryBuild.bytecode.object as Hex, - abi: worldFactoryAbi, - args: [initModule], - }); - const worldFactory = getCreate2Address({ from: deployerAddress, bytecode: worldFactoryBytecode, salt }); - - return { - AccessManagementSystem: { - bytecode: accessManagementSystemBytecode, - deployedBytecodeSize: accessManagementSystemDeployedBytecodeSize, - label: "AccessManagementSystem", - address: accessManagementSystem, - }, - BalanceTransferSystem: { - bytecode: balanceTransferSystemBytecode, - deployedBytecodeSize: balanceTransferSystemDeployedBytecodeSize, - label: "BalanceTransferSystem", - address: balanceTransferSystem, - }, - BatchCallSystem: { - bytecode: batchCallSystemBytecode, - deployedBytecodeSize: batchCallSystemDeployedBytecodeSize, - label: "BatchCallSystem", - address: batchCallSystem, - }, - RegistrationSystem: { - bytecode: registrationBytecode, - deployedBytecodeSize: registrationDeployedBytecodeSize, - label: "RegistrationSystem", - address: registration, - }, - InitModule: { - bytecode: initModuleBytecode, - deployedBytecodeSize: initModuleDeployedBytecodeSize, - label: "InitModule", - address: initModule, - }, - WorldFactory: { - bytecode: worldFactoryBytecode, - deployedBytecodeSize: worldFactoryDeployedBytecodeSize, - label: "WorldFactory", - address: worldFactory, - }, - }; -} +import { getWorldFactoryContracts } from "./getWorldFactoryContracts"; export async function ensureWorldFactory( client: Client, diff --git a/packages/cli/src/deploy/getWorldFactoryContracts.ts b/packages/cli/src/deploy/getWorldFactoryContracts.ts new file mode 100644 index 0000000000..59f9573933 --- /dev/null +++ b/packages/cli/src/deploy/getWorldFactoryContracts.ts @@ -0,0 +1,96 @@ +import accessManagementSystemBuild from "@latticexyz/world/out/AccessManagementSystem.sol/AccessManagementSystem.json" assert { type: "json" }; +import balanceTransferSystemBuild from "@latticexyz/world/out/BalanceTransferSystem.sol/BalanceTransferSystem.json" assert { type: "json" }; +import batchCallSystemBuild from "@latticexyz/world/out/BatchCallSystem.sol/BatchCallSystem.json" assert { type: "json" }; +import registrationSystemBuild from "@latticexyz/world/out/RegistrationSystem.sol/RegistrationSystem.json" assert { type: "json" }; +import initModuleBuild from "@latticexyz/world/out/InitModule.sol/InitModule.json" assert { type: "json" }; +import initModuleAbi from "@latticexyz/world/out/InitModule.sol/InitModule.abi.json" assert { type: "json" }; +import worldFactoryBuild from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.json" assert { type: "json" }; +import worldFactoryAbi from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json" assert { type: "json" }; +import { Hex, getCreate2Address, encodeDeployData, size } from "viem"; +import { salt } from "./common"; +import { Contract } from "./ensureContract"; + +export function getWorldFactoryContracts(deployerAddress: Hex): Record { + const accessManagementSystemDeployedBytecodeSize = size(accessManagementSystemBuild.deployedBytecode.object as Hex); + const accessManagementSystemBytecode = accessManagementSystemBuild.bytecode.object as Hex; + const accessManagementSystem = getCreate2Address({ + from: deployerAddress, + bytecode: accessManagementSystemBytecode, + salt, + }); + + const balanceTransferSystemDeployedBytecodeSize = size(balanceTransferSystemBuild.deployedBytecode.object as Hex); + const balanceTransferSystemBytecode = balanceTransferSystemBuild.bytecode.object as Hex; + const balanceTransferSystem = getCreate2Address({ + from: deployerAddress, + bytecode: balanceTransferSystemBytecode, + salt, + }); + + const batchCallSystemDeployedBytecodeSize = size(batchCallSystemBuild.deployedBytecode.object as Hex); + const batchCallSystemBytecode = batchCallSystemBuild.bytecode.object as Hex; + const batchCallSystem = getCreate2Address({ from: deployerAddress, bytecode: batchCallSystemBytecode, salt }); + + const registrationDeployedBytecodeSize = size(registrationSystemBuild.deployedBytecode.object as Hex); + const registrationBytecode = registrationSystemBuild.bytecode.object as Hex; + const registration = getCreate2Address({ + from: deployerAddress, + bytecode: registrationBytecode, + salt, + }); + + const initModuleDeployedBytecodeSize = size(initModuleBuild.deployedBytecode.object as Hex); + const initModuleBytecode = encodeDeployData({ + bytecode: initModuleBuild.bytecode.object as Hex, + abi: initModuleAbi, + args: [accessManagementSystem, balanceTransferSystem, batchCallSystem, registration], + }); + const initModule = getCreate2Address({ from: deployerAddress, bytecode: initModuleBytecode, salt }); + + const worldFactoryDeployedBytecodeSize = size(worldFactoryBuild.deployedBytecode.object as Hex); + const worldFactoryBytecode = encodeDeployData({ + bytecode: worldFactoryBuild.bytecode.object as Hex, + abi: worldFactoryAbi, + args: [initModule], + }); + const worldFactory = getCreate2Address({ from: deployerAddress, bytecode: worldFactoryBytecode, salt }); + + return { + AccessManagementSystem: { + bytecode: accessManagementSystemBytecode, + deployedBytecodeSize: accessManagementSystemDeployedBytecodeSize, + label: "AccessManagementSystem", + address: accessManagementSystem, + }, + BalanceTransferSystem: { + bytecode: balanceTransferSystemBytecode, + deployedBytecodeSize: balanceTransferSystemDeployedBytecodeSize, + label: "BalanceTransferSystem", + address: balanceTransferSystem, + }, + BatchCallSystem: { + bytecode: batchCallSystemBytecode, + deployedBytecodeSize: batchCallSystemDeployedBytecodeSize, + label: "BatchCallSystem", + address: batchCallSystem, + }, + RegistrationSystem: { + bytecode: registrationBytecode, + deployedBytecodeSize: registrationDeployedBytecodeSize, + label: "RegistrationSystem", + address: registration, + }, + InitModule: { + bytecode: initModuleBytecode, + deployedBytecodeSize: initModuleDeployedBytecodeSize, + label: "InitModule", + address: initModule, + }, + WorldFactory: { + bytecode: worldFactoryBytecode, + deployedBytecodeSize: worldFactoryDeployedBytecodeSize, + label: "WorldFactory", + address: worldFactory, + }, + }; +} diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index f5c6e09ae6..ef097b0ce6 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -3,8 +3,8 @@ import { Hex, getCreate2Address } from "viem"; import { salt } from "./deploy/common"; import { deployer } from "./deploy/ensureDeployer"; import { MUDError } from "@latticexyz/common/errors"; -import { getWorldFactoryContracts } from "./deploy/ensureWorldFactory"; import { Contract } from "./deploy/ensureContract"; +import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; type VerifyOptions = { foundryProfile?: string; From 49a0b22f7e285d9ee93926ffeb1fcfd127270870 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 17 Apr 2024 19:58:46 +0100 Subject: [PATCH 27/62] docs: change description to mud config --- packages/cli/src/commands/build.ts | 2 +- packages/cli/src/commands/tablegen.ts | 2 +- packages/cli/src/commands/trace.ts | 2 +- packages/cli/src/commands/verify.ts | 2 +- packages/cli/src/commands/worldgen.ts | 2 +- packages/cli/src/runDeploy.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index b36477243f..39dee7e71c 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -17,7 +17,7 @@ const commandModule: CommandModule = { builder(yargs) { return yargs.options({ - configPath: { type: "string", desc: "Path to the config file" }, + configPath: { type: "string", desc: "Path to the MUD config file" }, profile: { type: "string", desc: "The foundry profile to use" }, }); }, diff --git a/packages/cli/src/commands/tablegen.ts b/packages/cli/src/commands/tablegen.ts index 48a6dddb3e..bf237e99dc 100644 --- a/packages/cli/src/commands/tablegen.ts +++ b/packages/cli/src/commands/tablegen.ts @@ -16,7 +16,7 @@ const commandModule: CommandModule = { builder(yargs) { return yargs.options({ - configPath: { type: "string", desc: "Path to the config file" }, + configPath: { type: "string", desc: "Path to the MUD config file" }, }); }, diff --git a/packages/cli/src/commands/trace.ts b/packages/cli/src/commands/trace.ts index 6d7fa8d1ee..2ce3c1ee43 100644 --- a/packages/cli/src/commands/trace.ts +++ b/packages/cli/src/commands/trace.ts @@ -43,7 +43,7 @@ const commandModule: CommandModule = { type: "string", description: "World contract address. Defaults to the value from worlds.json, based on rpc's chainId", }, - configPath: { type: "string", description: "Path to the config file" }, + configPath: { type: "string", description: "Path to the MUD config file" }, profile: { type: "string", description: "The foundry profile to use" }, srcDir: { type: "string", description: "Source directory. Defaults to foundry src directory." }, rpc: { type: "string", description: "json rpc endpoint. Defaults to foundry's configured eth_rpc_url" }, diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 5dcd4aaaeb..4216161792 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -26,7 +26,7 @@ const commandModule: CommandModule = { builder(yargs) { return yargs.options({ - configPath: { type: "string", desc: "Path to the config file" }, + configPath: { type: "string", desc: "Path to the MUD config file" }, profile: { type: "string", desc: "The foundry profile to use" }, worldAddress: { type: "string", desc: "Verify an existing World at the given address" }, srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." }, diff --git a/packages/cli/src/commands/worldgen.ts b/packages/cli/src/commands/worldgen.ts index a599b813d4..3a87a7348b 100644 --- a/packages/cli/src/commands/worldgen.ts +++ b/packages/cli/src/commands/worldgen.ts @@ -21,7 +21,7 @@ const commandModule: CommandModule = { builder(yargs) { return yargs.options({ - configPath: { type: "string", desc: "Path to the config file" }, + configPath: { type: "string", desc: "Path to the MUD config file" }, clean: { type: "boolean", desc: "Clear the worldgen directory before generating new interfaces (defaults to true)", diff --git a/packages/cli/src/runDeploy.ts b/packages/cli/src/runDeploy.ts index 0d9cf1ca88..587a6b7bf1 100644 --- a/packages/cli/src/runDeploy.ts +++ b/packages/cli/src/runDeploy.ts @@ -17,7 +17,7 @@ import { WorldDeploy } from "./deploy/common"; import { build } from "./build"; export const deployOptions = { - configPath: { type: "string", desc: "Path to the config file" }, + configPath: { type: "string", desc: "Path to the MUD config file" }, printConfig: { type: "boolean", desc: "Print the resolved config" }, profile: { type: "string", desc: "The foundry profile to use" }, saveDeployment: { type: "boolean", desc: "Save the deployment info to a file", default: true }, From f404cce63f34d6109278a1d23022f5783bd9a4ca Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 11:52:45 +0100 Subject: [PATCH 28/62] refactor: move verify contract to seperate file --- packages/cli/src/commands/verify.ts | 6 +- .../src/deploy/getWorldFactoryContracts.ts | 12 +- packages/cli/src/verify.ts | 108 +++++++++--------- packages/cli/src/verifyContract.ts | 69 +++++++++++ 4 files changed, 128 insertions(+), 67 deletions(-) create mode 100644 packages/cli/src/verifyContract.ts diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 4216161792..3927d2d31d 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -54,9 +54,8 @@ const commandModule: CommandModule = { const contractData = getContractData(`${name}.sol`, name, outDir); return { - label: name, + name, bytecode: contractData.bytecode, - deployedBytecodeSize: contractData.deployedBytecodeSize, }; }); @@ -66,9 +65,8 @@ const commandModule: CommandModule = { getContractData(`${mod.name}.sol`, mod.name, outDir); return { - label: mod.name, + name: mod.name, bytecode: contractData.bytecode, - deployedBytecodeSize: contractData.deployedBytecodeSize, }; }); diff --git a/packages/cli/src/deploy/getWorldFactoryContracts.ts b/packages/cli/src/deploy/getWorldFactoryContracts.ts index 59f9573933..511d38fcbc 100644 --- a/packages/cli/src/deploy/getWorldFactoryContracts.ts +++ b/packages/cli/src/deploy/getWorldFactoryContracts.ts @@ -59,37 +59,37 @@ export function getWorldFactoryContracts(deployerAddress: Hex): Record verifyContractFromBytecode(deployer, contract, rpc, verifier, foundryProfile)), + systems.map(({ name, bytecode }) => + verifyContractCreate2DefaultSalt( + { + name, + from: deployer, + bytecode, + rpc, + verifier, + }, + { profile: foundryProfile }, + ), + ), ); await Promise.all( - Object.values(getWorldFactoryContracts(deployer)).map((contract) => - verifyContractFromBytecode(deployer, contract, rpc, verifier, foundryProfile, "node_modules/@latticexyz/world"), + Object.entries(getWorldFactoryContracts(deployer)).map(([name, { bytecode }]) => + verifyContractCreate2DefaultSalt( + { + name, + from: deployer, + bytecode, + rpc, + verifier, + }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ), ), ); await Promise.all( - modules.map((contract) => - verifyContractFromBytecode( - deployer, - contract, - rpc, - verifier, - foundryProfile, - "node_modules/@latticexyz/world-modules", + modules.map(({ name, bytecode }) => + verifyContractCreate2DefaultSalt( + { + name: name, + from: deployer, + bytecode: bytecode, + rpc, + verifier, + }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world-modules", + }, ), ), ); - verifyContract(worldAddress, "World", rpc, verifier, "node_modules/@latticexyz/world"); + verifyContract( + { name: "World", address: worldAddress, rpc, verifier }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ); } diff --git a/packages/cli/src/verifyContract.ts b/packages/cli/src/verifyContract.ts new file mode 100644 index 0000000000..85380f5b4a --- /dev/null +++ b/packages/cli/src/verifyContract.ts @@ -0,0 +1,69 @@ +import { forge } from "@latticexyz/common/foundry"; +import { Address, ByteArray, Hex, getCreate2Address } from "viem"; +import { salt } from "./deploy/common"; + +type ForgeOptions = { profile?: string; silent?: boolean; env?: NodeJS.ProcessEnv; cwd?: string }; + +type Create2Options = { + bytecode: ByteArray | Hex; + from: Address; + salt: ByteArray | Hex; +}; + +export async function verifyContract( + { + address, + name, + rpc, + verifier, + }: { + address: Hex; + name: string; + rpc: string; + verifier?: string; + }, + options?: ForgeOptions, +) { + if (verifier) { + await forge(["verify-contract", address, name, "--rpc-url", rpc, "--verifier", verifier], options); + } else { + await forge(["verify-contract", address, name, "--rpc-url", rpc], options); + } +} + +export async function verifyContractCreate2( + { + name, + rpc, + verifier, + from, + bytecode, + salt, + }: { + name: string; + rpc: string; + verifier?: string; + } & Create2Options, + options?: ForgeOptions, +) { + const address = getCreate2Address({ from, bytecode, salt }); + + return verifyContract({ address, name, rpc, verifier }, options); +} + +export async function verifyContractCreate2DefaultSalt( + { + name, + rpc, + verifier, + from, + bytecode, + }: { + name: string; + rpc: string; + verifier?: string; + } & Omit, + options?: ForgeOptions, +) { + return verifyContractCreate2({ name, rpc, verifier, from, bytecode, salt }, options); +} From 26dd94840ba17675cb51b6d8714dbdc5c39b7c38 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 12:00:25 +0100 Subject: [PATCH 29/62] feat: verifier url --- packages/cli/src/commands/verify.ts | 5 +++++ packages/cli/src/verify.ts | 7 ++++++- packages/cli/src/verifyContract.ts | 22 +++++++++++++++++----- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 3927d2d31d..1cc7dbade9 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -31,6 +31,10 @@ const commandModule: CommandModule = { worldAddress: { type: "string", desc: "Verify an existing World at the given address" }, srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." }, verifier: { type: "string", desc: "The verifier to use" }, + verifierUrl: { + type: "string", + desc: "The verification provider.", + }, }); }, @@ -78,6 +82,7 @@ const commandModule: CommandModule = { modules, worldAddress: opts.worldAddress as Hex, verifier: opts.verifier, + verifierUrl: opts.verifierUrl, }); } catch (error) { logError(error); diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index d1da1783b3..6d07534096 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -7,6 +7,7 @@ import { verifyContract, verifyContractCreate2DefaultSalt } from "./verifyContra type VerifyOptions = { foundryProfile?: string; verifier?: string; + verifierUrl?: string; systems: { name: string; bytecode: Hex }[]; modules: { name: string; bytecode: Hex }[]; worldAddress: Hex; @@ -18,6 +19,7 @@ export async function verify({ modules, worldAddress, verifier, + verifierUrl, }: VerifyOptions): Promise { const rpc = await getRpcUrl(foundryProfile); @@ -30,6 +32,7 @@ export async function verify({ bytecode, rpc, verifier, + verifierUrl, }, { profile: foundryProfile }, ), @@ -45,6 +48,7 @@ export async function verify({ bytecode, rpc, verifier, + verifierUrl, }, { profile: foundryProfile, @@ -63,6 +67,7 @@ export async function verify({ bytecode: bytecode, rpc, verifier, + verifierUrl, }, { profile: foundryProfile, @@ -73,7 +78,7 @@ export async function verify({ ); verifyContract( - { name: "World", address: worldAddress, rpc, verifier }, + { name: "World", address: worldAddress, rpc, verifier, verifierUrl }, { profile: foundryProfile, cwd: "node_modules/@latticexyz/world", diff --git a/packages/cli/src/verifyContract.ts b/packages/cli/src/verifyContract.ts index 85380f5b4a..ec7ffe71b3 100644 --- a/packages/cli/src/verifyContract.ts +++ b/packages/cli/src/verifyContract.ts @@ -16,19 +16,27 @@ export async function verifyContract( name, rpc, verifier, + verifierUrl, }: { address: Hex; name: string; rpc: string; verifier?: string; + verifierUrl?: string; }, options?: ForgeOptions, ) { + const args = ["verify-contract", address, name, "--rpc-url", rpc]; + if (verifier) { - await forge(["verify-contract", address, name, "--rpc-url", rpc, "--verifier", verifier], options); - } else { - await forge(["verify-contract", address, name, "--rpc-url", rpc], options); + args.push("--verifier"); + args.push(verifier); + } + if (verifierUrl) { + args.push("--verifier-url"); + args.push(verifierUrl); } + await forge(args, options); } export async function verifyContractCreate2( @@ -36,6 +44,7 @@ export async function verifyContractCreate2( name, rpc, verifier, + verifierUrl, from, bytecode, salt, @@ -43,12 +52,13 @@ export async function verifyContractCreate2( name: string; rpc: string; verifier?: string; + verifierUrl?: string; } & Create2Options, options?: ForgeOptions, ) { const address = getCreate2Address({ from, bytecode, salt }); - return verifyContract({ address, name, rpc, verifier }, options); + return verifyContract({ address, name, rpc, verifier, verifierUrl }, options); } export async function verifyContractCreate2DefaultSalt( @@ -56,14 +66,16 @@ export async function verifyContractCreate2DefaultSalt( name, rpc, verifier, + verifierUrl, from, bytecode, }: { name: string; rpc: string; verifier?: string; + verifierUrl?: string; } & Omit, options?: ForgeOptions, ) { - return verifyContractCreate2({ name, rpc, verifier, from, bytecode, salt }, options); + return verifyContractCreate2({ name, rpc, verifier, verifierUrl, from, bytecode, salt }, options); } From 1e497a6d4ea6ba7192be4b550028f7fa07e03610 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 12:01:08 +0100 Subject: [PATCH 30/62] refactor: push --- packages/cli/src/verifyContract.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/verifyContract.ts b/packages/cli/src/verifyContract.ts index ec7ffe71b3..4c674b5f50 100644 --- a/packages/cli/src/verifyContract.ts +++ b/packages/cli/src/verifyContract.ts @@ -29,12 +29,10 @@ export async function verifyContract( const args = ["verify-contract", address, name, "--rpc-url", rpc]; if (verifier) { - args.push("--verifier"); - args.push(verifier); + args.push("--verifier", verifier); } if (verifierUrl) { - args.push("--verifier-url"); - args.push(verifierUrl); + args.push("--verifier-url", verifierUrl); } await forge(args, options); } From 181931969ee4ca3e7424d54ed8d10cee1938faa7 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 12:06:54 +0100 Subject: [PATCH 31/62] refactor: verificationOptions --- packages/cli/src/verifyContract.ts | 44 ++++++++---------------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/packages/cli/src/verifyContract.ts b/packages/cli/src/verifyContract.ts index 4c674b5f50..c7b0fa8f32 100644 --- a/packages/cli/src/verifyContract.ts +++ b/packages/cli/src/verifyContract.ts @@ -2,6 +2,14 @@ import { forge } from "@latticexyz/common/foundry"; import { Address, ByteArray, Hex, getCreate2Address } from "viem"; import { salt } from "./deploy/common"; +type VerificationOptions = { + address: Hex; + name: string; + rpc: string; + verifier?: string; + verifierUrl?: string; +}; + type ForgeOptions = { profile?: string; silent?: boolean; env?: NodeJS.ProcessEnv; cwd?: string }; type Create2Options = { @@ -11,19 +19,7 @@ type Create2Options = { }; export async function verifyContract( - { - address, - name, - rpc, - verifier, - verifierUrl, - }: { - address: Hex; - name: string; - rpc: string; - verifier?: string; - verifierUrl?: string; - }, + { address, name, rpc, verifier, verifierUrl }: VerificationOptions, options?: ForgeOptions, ) { const args = ["verify-contract", address, name, "--rpc-url", rpc]; @@ -38,20 +34,7 @@ export async function verifyContract( } export async function verifyContractCreate2( - { - name, - rpc, - verifier, - verifierUrl, - from, - bytecode, - salt, - }: { - name: string; - rpc: string; - verifier?: string; - verifierUrl?: string; - } & Create2Options, + { name, rpc, verifier, verifierUrl, from, bytecode, salt }: Omit & Create2Options, options?: ForgeOptions, ) { const address = getCreate2Address({ from, bytecode, salt }); @@ -67,12 +50,7 @@ export async function verifyContractCreate2DefaultSalt( verifierUrl, from, bytecode, - }: { - name: string; - rpc: string; - verifier?: string; - verifierUrl?: string; - } & Omit, + }: Omit & Omit, options?: ForgeOptions, ) { return verifyContractCreate2({ name, rpc, verifier, verifierUrl, from, bytecode, salt }, options); From 9e65089124db7710d4c9d0fed7c4005725fe7b25 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 12:34:39 +0100 Subject: [PATCH 32/62] fix: option --- packages/cli/src/commands/verify.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 1cc7dbade9..1d9db65a51 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -17,6 +17,7 @@ type Options = { profile?: string; srcDir?: string; verifier?: string; + verifierUrl?: string; }; const commandModule: CommandModule = { From ba67a3bbfa7a9654bcc7c36431b330de28335e8b Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 12:41:49 +0100 Subject: [PATCH 33/62] refactor: use v2 config more --- packages/cli/src/commands/verify.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 1d9db65a51..ee81f43876 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -46,14 +46,14 @@ const commandModule: CommandModule = { const profile = opts.profile ?? process.env.FOUNDRY_PROFILE; - const configV2 = (await loadConfig(opts.configPath)) as WorldConfig; - const config = worldToV1(configV2); + const mudConfig = (await loadConfig(opts.configPath)) as WorldConfig; + const configV1 = worldToV1(mudConfig); const srcDir = opts.srcDir ?? (await getSrcDirectory(profile)); const outDir = await getOutDirectory(profile); const contractNames = getExistingContracts(srcDir).map(({ basename }) => basename); - const resolvedWorldConfig = resolveWorldConfig(config, contractNames); + const resolvedWorldConfig = resolveWorldConfig(configV1, contractNames); const systems = Object.keys(resolvedWorldConfig.systems).map((name) => { const contractData = getContractData(`${name}.sol`, name, outDir); @@ -64,7 +64,7 @@ const commandModule: CommandModule = { }; }); - const modules = config.modules.map((mod) => { + const modules = mudConfig.modules.map((mod) => { const contractData = defaultModuleContracts.find((defaultMod) => defaultMod.name === mod.name) ?? getContractData(`${mod.name}.sol`, mod.name, outDir); From 1b0d2b9e537d7d8ce34ce01528eeb7652b852cdf Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 12:47:08 +0100 Subject: [PATCH 34/62] rename: config --- packages/cli/src/commands/verify.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index ee81f43876..5729b37cb6 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -46,8 +46,8 @@ const commandModule: CommandModule = { const profile = opts.profile ?? process.env.FOUNDRY_PROFILE; - const mudConfig = (await loadConfig(opts.configPath)) as WorldConfig; - const configV1 = worldToV1(mudConfig); + const config = (await loadConfig(opts.configPath)) as WorldConfig; + const configV1 = worldToV1(config); const srcDir = opts.srcDir ?? (await getSrcDirectory(profile)); const outDir = await getOutDirectory(profile); @@ -64,7 +64,7 @@ const commandModule: CommandModule = { }; }); - const modules = mudConfig.modules.map((mod) => { + const modules = config.modules.map((mod) => { const contractData = defaultModuleContracts.find((defaultMod) => defaultMod.name === mod.name) ?? getContractData(`${mod.name}.sol`, mod.name, outDir); From f18658051c7b44ff06aceb961ad6889080ae39e0 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 12:52:12 +0100 Subject: [PATCH 35/62] chore: comment --- packages/cli/src/commands/verify.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 5729b37cb6..8ce3377c0d 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -47,6 +47,8 @@ const commandModule: CommandModule = { const profile = opts.profile ?? process.env.FOUNDRY_PROFILE; const config = (await loadConfig(opts.configPath)) as WorldConfig; + + // Get user-defined systems const configV1 = worldToV1(config); const srcDir = opts.srcDir ?? (await getSrcDirectory(profile)); @@ -64,6 +66,7 @@ const commandModule: CommandModule = { }; }); + // Get modules const modules = config.modules.map((mod) => { const contractData = defaultModuleContracts.find((defaultMod) => defaultMod.name === mod.name) ?? From e7aacf9c08c251b95dbad3398608c752d530b793 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 13:54:39 +0100 Subject: [PATCH 36/62] feat: promise.all --- packages/cli/src/verify.ts | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 6d07534096..d834e1d61c 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -23,8 +23,8 @@ export async function verify({ }: VerifyOptions): Promise { const rpc = await getRpcUrl(foundryProfile); - await Promise.all( - systems.map(({ name, bytecode }) => + await Promise.all([ + ...systems.map(({ name, bytecode }) => verifyContractCreate2DefaultSalt( { name, @@ -37,10 +37,7 @@ export async function verify({ { profile: foundryProfile }, ), ), - ); - - await Promise.all( - Object.entries(getWorldFactoryContracts(deployer)).map(([name, { bytecode }]) => + ...Object.entries(getWorldFactoryContracts(deployer)).map(([name, { bytecode }]) => verifyContractCreate2DefaultSalt( { name, @@ -56,10 +53,7 @@ export async function verify({ }, ), ), - ); - - await Promise.all( - modules.map(({ name, bytecode }) => + ...modules.map(({ name, bytecode }) => verifyContractCreate2DefaultSalt( { name: name, @@ -75,13 +69,12 @@ export async function verify({ }, ), ), - ); - - verifyContract( - { name: "World", address: worldAddress, rpc, verifier, verifierUrl }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }, - ); + verifyContract( + { name: "World", address: worldAddress, rpc, verifier, verifierUrl }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ), + ]); } From 29c3bcceb8fc59fdd6af61da9f0cd1be1879e22b Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 14:05:59 +0100 Subject: [PATCH 37/62] feat: pqueue --- packages/cli/package.json | 1 + packages/cli/src/commands/verify.ts | 2 +- packages/cli/src/verify.ts | 119 ++++++++++++++++------------ pnpm-lock.yaml | 57 +++---------- 4 files changed, 81 insertions(+), 98 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 80cedb8da2..b98fcfafd8 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -55,6 +55,7 @@ "glob": "^8.0.3", "nice-grpc-web": "^2.0.1", "openurl": "^1.1.1", + "p-queue": "^7.4.1", "p-retry": "^5.1.2", "path": "^0.12.7", "rxjs": "7.5.5", diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 8ce3377c0d..2ef577806b 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -92,7 +92,7 @@ const commandModule: CommandModule = { logError(error); process.exit(1); } - process.exit(0); + // process.exit(0); }, }; diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index d834e1d61c..8026ca1c53 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -3,6 +3,7 @@ import { Hex } from "viem"; import { deployer } from "./deploy/ensureDeployer"; import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; import { verifyContract, verifyContractCreate2DefaultSalt } from "./verifyContract"; +import PQueue from "p-queue"; type VerifyOptions = { foundryProfile?: string; @@ -23,58 +24,78 @@ export async function verify({ }: VerifyOptions): Promise { const rpc = await getRpcUrl(foundryProfile); - await Promise.all([ - ...systems.map(({ name, bytecode }) => - verifyContractCreate2DefaultSalt( - { - name, - from: deployer, - bytecode, - rpc, - verifier, - verifierUrl, - }, - { profile: foundryProfile }, - ), + const queueConcurrency = 1; + const verifyQueue = new PQueue({ concurrency: queueConcurrency }); + + const tasks = [ + ...systems.map( + ({ name, bytecode }) => + () => + verifyContractCreate2DefaultSalt( + { + name, + from: deployer, + bytecode, + rpc, + verifier, + verifierUrl, + }, + { profile: foundryProfile }, + ).catch((error) => { + console.error(`Error verifying system contract ${name}:`, error); + }), ), - ...Object.entries(getWorldFactoryContracts(deployer)).map(([name, { bytecode }]) => - verifyContractCreate2DefaultSalt( - { - name, - from: deployer, - bytecode, - rpc, - verifier, - verifierUrl, - }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }, - ), + ...Object.entries(getWorldFactoryContracts(deployer)).map( + ([name, { bytecode }]) => + () => + verifyContractCreate2DefaultSalt( + { + name, + from: deployer, + bytecode, + rpc, + verifier, + verifierUrl, + }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ).catch((error) => { + console.error(`Error verifying world factory contract ${name}:`, error); + }), ), - ...modules.map(({ name, bytecode }) => - verifyContractCreate2DefaultSalt( - { - name: name, - from: deployer, - bytecode: bytecode, - rpc, - verifier, - verifierUrl, - }, + ...modules.map( + ({ name, bytecode }) => + () => + verifyContractCreate2DefaultSalt( + { + name: name, + from: deployer, + bytecode: bytecode, + rpc, + verifier, + verifierUrl, + }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world-modules", + }, + ).catch((error) => { + console.error(`Error verifying module contract ${name}:`, error); + }), + ), + () => + verifyContract( + { name: "World", address: worldAddress, rpc, verifier, verifierUrl }, { profile: foundryProfile, - cwd: "node_modules/@latticexyz/world-modules", + cwd: "node_modules/@latticexyz/world", }, - ), - ), - verifyContract( - { name: "World", address: worldAddress, rpc, verifier, verifierUrl }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }, - ), - ]); + ).catch((error) => { + console.error(`Error verifying World contract:`, error); + }), + ]; + + tasks.forEach((task) => verifyQueue.add(task)); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2bba08a5cc..217e3ace4a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -205,6 +205,9 @@ importers: openurl: specifier: ^1.1.1 version: 1.1.1 + p-queue: + specifier: ^7.4.1 + version: 7.4.1 p-retry: specifier: ^5.1.2 version: 5.1.2 @@ -656,10 +659,10 @@ importers: version: 29.5.0(@types/node@18.15.11) ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.24.4)(esbuild@0.17.17)(jest@29.5.0)(typescript@5.4.5) + version: 29.0.5(@babel/core@7.24.4)(esbuild@0.17.17)(jest@29.5.0)(typescript@5.4.2) tsup: specifier: ^6.7.0 - version: 6.7.0(typescript@5.4.5) + version: 6.7.0(postcss@8.4.23)(typescript@5.4.2) type-fest: specifier: ^2.14.0 version: 2.14.0 @@ -1020,10 +1023,10 @@ importers: version: 29.5.0(@types/node@18.15.11) ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.24.4)(esbuild@0.17.17)(jest@29.5.0)(typescript@5.4.5) + version: 29.0.5(@babel/core@7.24.4)(esbuild@0.17.17)(jest@29.5.0)(typescript@5.4.2) tsup: specifier: ^6.7.0 - version: 6.7.0(typescript@5.4.5) + version: 6.7.0(postcss@8.4.23)(typescript@5.4.2) packages/world: dependencies: @@ -10775,7 +10778,7 @@ packages: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} dev: true - /ts-jest@29.0.5(@babel/core@7.24.4)(esbuild@0.17.17)(jest@29.5.0)(typescript@5.4.5): + /ts-jest@29.0.5(@babel/core@7.24.4)(esbuild@0.17.17)(jest@29.5.0)(typescript@5.4.2): resolution: {integrity: sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -10806,7 +10809,7 @@ packages: lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.5.0 - typescript: 5.4.5 + typescript: 5.4.2 yargs-parser: 21.1.1 dev: true @@ -10884,42 +10887,6 @@ packages: - ts-node dev: true - /tsup@6.7.0(typescript@5.4.5): - resolution: {integrity: sha512-L3o8hGkaHnu5TdJns+mCqFsDBo83bJ44rlK7e6VdanIvpea4ArPcU3swWGsLVbXak1PqQx/V+SSmFPujBK+zEQ==} - engines: {node: '>=14.18'} - hasBin: true - peerDependencies: - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.1.0' - peerDependenciesMeta: - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true - dependencies: - bundle-require: 4.0.1(esbuild@0.17.17) - cac: 6.7.14 - chokidar: 3.5.3 - debug: 4.3.4 - esbuild: 0.17.17 - execa: 5.1.1 - globby: 11.1.0 - joycon: 3.1.1 - postcss-load-config: 3.1.4(postcss@8.4.23) - resolve-from: 5.0.0 - rollup: 3.21.8 - source-map: 0.8.0-beta.0 - sucrase: 3.32.0 - tree-kill: 1.2.2 - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - ts-node - dev: true - /tsx@3.12.6: resolution: {integrity: sha512-q93WgS3lBdHlPgS0h1i+87Pt6n9K/qULIMNYZo07nSeu2z5QE2CellcAZfofVXBo2tQg9av2ZcRMQ2S2i5oadQ==} hasBin: true @@ -11081,12 +11048,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - /typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} - engines: {node: '>=14.17'} - hasBin: true - dev: true - /ufo@1.3.2: resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} dev: true From 4b160a5cb6fc7b0979556a692cf05dae26443724 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 14:09:51 +0100 Subject: [PATCH 38/62] reset example --- examples/minimal/packages/contracts/foundry.toml | 3 --- examples/minimal/packages/contracts/package.json | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/examples/minimal/packages/contracts/foundry.toml b/examples/minimal/packages/contracts/foundry.toml index 22fd64d7d9..3eb96af5e6 100644 --- a/examples/minimal/packages/contracts/foundry.toml +++ b/examples/minimal/packages/contracts/foundry.toml @@ -22,6 +22,3 @@ fs_permissions = [{ access = "read", path = "./"}] [profile.lattice-testnet] eth_rpc_url = "https://follower.testnet-chain.linfra.xyz" - -[profile.holesky] -eth_rpc_url = "https://ethereum-holesky.publicnode.com" diff --git a/examples/minimal/packages/contracts/package.json b/examples/minimal/packages/contracts/package.json index f37210808d..cb4a8c3286 100644 --- a/examples/minimal/packages/contracts/package.json +++ b/examples/minimal/packages/contracts/package.json @@ -6,7 +6,6 @@ "scripts": { "build": "mud build", "clean": "forge clean && rimraf src/codegen", - "deploy:holesky": "pnpm run build && mud deploy --profile=holesky", "deploy:local": "pnpm run build && mud deploy", "deploy:testnet": "pnpm run build && mud deploy --profile=lattice-testnet", "dev": "pnpm mud dev-contracts", @@ -14,8 +13,7 @@ "lint": "pnpm run prettier && pnpm run solhint", "prettier": "prettier --write 'src/**/*.sol'", "solhint": "solhint --config ./.solhint.json 'src/**/*.sol' --fix", - "test": "mud test", - "verify": "pnpm mud verify --profile=holesky --worldAddress=0xcf6179d4c4ddc99ba29709d87c6bf9b0fefae0fc --verifier sourcify" + "test": "mud test" }, "devDependencies": { "@latticexyz/cli": "link:../../../../packages/cli", From 6977d45eb8ec5f5b627f0c2263dcd4455a50eab2 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 14:11:42 +0100 Subject: [PATCH 39/62] refactor: constant --- packages/cli/src/verify.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 8026ca1c53..f35a012762 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -24,8 +24,7 @@ export async function verify({ }: VerifyOptions): Promise { const rpc = await getRpcUrl(foundryProfile); - const queueConcurrency = 1; - const verifyQueue = new PQueue({ concurrency: queueConcurrency }); + const verifyQueue = new PQueue({ concurrency: 1 }); const tasks = [ ...systems.map( From de481cfbfab8bf05b17cd79978b42196efa765a2 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 14:21:51 +0100 Subject: [PATCH 40/62] fix: type error --- packages/cli/src/commands/verify.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 2ef577806b..be612597b6 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -2,7 +2,8 @@ import type { CommandModule } from "yargs"; import { verify } from "../verify"; import { logError } from "../utils/errors"; import { loadConfig } from "@latticexyz/config/node"; -import { WorldConfig, resolveWorldConfig } from "@latticexyz/world/internal"; +import { World as WorldConfig } from "@latticexyz/world"; +import { resolveWorldConfig } from "@latticexyz/world/internal"; import { worldToV1 } from "@latticexyz/world/config/v2"; import { getOutDirectory, getSrcDirectory } from "@latticexyz/common/foundry"; import { getExistingContracts } from "../utils/getExistingContracts"; From 3d62480654b6e242443615bdac58b09ad3ede688 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 17:09:53 +0100 Subject: [PATCH 41/62] fix: world address is required --- packages/cli/src/commands/verify.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index be612597b6..b0d0a193d2 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -10,10 +10,9 @@ import { getExistingContracts } from "../utils/getExistingContracts"; import { getContractData } from "../utils/getContractData"; import { defaultModuleContracts } from "../utils/defaultModuleContracts"; import { Hex } from "viem"; -import { MUDError } from "@latticexyz/common/errors"; type Options = { - worldAddress?: string; + worldAddress: string; configPath?: string; profile?: string; srcDir?: string; @@ -28,9 +27,9 @@ const commandModule: CommandModule = { builder(yargs) { return yargs.options({ + worldAddress: { type: "string", required: true, desc: "Verify an existing World at the given address" }, configPath: { type: "string", desc: "Path to the MUD config file" }, profile: { type: "string", desc: "The foundry profile to use" }, - worldAddress: { type: "string", desc: "Verify an existing World at the given address" }, srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." }, verifier: { type: "string", desc: "The verifier to use" }, verifierUrl: { @@ -41,10 +40,6 @@ const commandModule: CommandModule = { }, async handler(opts) { - if (!opts.worldAddress) { - throw new MUDError("Need a world address"); - } - const profile = opts.profile ?? process.env.FOUNDRY_PROFILE; const config = (await loadConfig(opts.configPath)) as WorldConfig; From 3ef2a300ccd35685a44c3ba9d21378a368865054 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 17:15:42 +0100 Subject: [PATCH 42/62] delete process.exit comment --- packages/cli/src/commands/verify.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index b0d0a193d2..a2962886a8 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -88,7 +88,6 @@ const commandModule: CommandModule = { logError(error); process.exit(1); } - // process.exit(0); }, }; From 3d9d25b28cffae7f003f303a95d28fdcf9590c0b Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 17:16:46 +0100 Subject: [PATCH 43/62] refactor: default salt --- packages/cli/src/verify.ts | 8 ++++---- packages/cli/src/verifyContract.ts | 20 +++----------------- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index f35a012762..845207892d 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -2,7 +2,7 @@ import { getRpcUrl } from "@latticexyz/common/foundry"; import { Hex } from "viem"; import { deployer } from "./deploy/ensureDeployer"; import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; -import { verifyContract, verifyContractCreate2DefaultSalt } from "./verifyContract"; +import { verifyContract, verifyContractCreate2 } from "./verifyContract"; import PQueue from "p-queue"; type VerifyOptions = { @@ -30,7 +30,7 @@ export async function verify({ ...systems.map( ({ name, bytecode }) => () => - verifyContractCreate2DefaultSalt( + verifyContractCreate2( { name, from: deployer, @@ -47,7 +47,7 @@ export async function verify({ ...Object.entries(getWorldFactoryContracts(deployer)).map( ([name, { bytecode }]) => () => - verifyContractCreate2DefaultSalt( + verifyContractCreate2( { name, from: deployer, @@ -67,7 +67,7 @@ export async function verify({ ...modules.map( ({ name, bytecode }) => () => - verifyContractCreate2DefaultSalt( + verifyContractCreate2( { name: name, from: deployer, diff --git a/packages/cli/src/verifyContract.ts b/packages/cli/src/verifyContract.ts index c7b0fa8f32..a7fc655d3d 100644 --- a/packages/cli/src/verifyContract.ts +++ b/packages/cli/src/verifyContract.ts @@ -1,6 +1,6 @@ import { forge } from "@latticexyz/common/foundry"; import { Address, ByteArray, Hex, getCreate2Address } from "viem"; -import { salt } from "./deploy/common"; +import { salt as defaultSalt } from "./deploy/common"; type VerificationOptions = { address: Hex; @@ -15,7 +15,7 @@ type ForgeOptions = { profile?: string; silent?: boolean; env?: NodeJS.ProcessEn type Create2Options = { bytecode: ByteArray | Hex; from: Address; - salt: ByteArray | Hex; + salt?: ByteArray | Hex; }; export async function verifyContract( @@ -37,21 +37,7 @@ export async function verifyContractCreate2( { name, rpc, verifier, verifierUrl, from, bytecode, salt }: Omit & Create2Options, options?: ForgeOptions, ) { - const address = getCreate2Address({ from, bytecode, salt }); + const address = getCreate2Address({ from, bytecode, salt: salt !== undefined ? salt : defaultSalt }); return verifyContract({ address, name, rpc, verifier, verifierUrl }, options); } - -export async function verifyContractCreate2DefaultSalt( - { - name, - rpc, - verifier, - verifierUrl, - from, - bytecode, - }: Omit & Omit, - options?: ForgeOptions, -) { - return verifyContractCreate2({ name, rpc, verifier, verifierUrl, from, bytecode, salt }, options); -} From e90af4001ac7fd5a4acf733bb1ef406b527ac828 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 17:32:25 +0100 Subject: [PATCH 44/62] refactor: verify takes union type --- packages/cli/src/verify.ts | 22 ++++++------ packages/cli/src/verifyContract.ts | 56 ++++++++++++++---------------- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 845207892d..c8c56a31c9 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -2,7 +2,7 @@ import { getRpcUrl } from "@latticexyz/common/foundry"; import { Hex } from "viem"; import { deployer } from "./deploy/ensureDeployer"; import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; -import { verifyContract, verifyContractCreate2 } from "./verifyContract"; +import { verifyContract } from "./verifyContract"; import PQueue from "p-queue"; type VerifyOptions = { @@ -30,14 +30,14 @@ export async function verify({ ...systems.map( ({ name, bytecode }) => () => - verifyContractCreate2( + verifyContract( { name, - from: deployer, - bytecode, rpc, verifier, verifierUrl, + from: deployer, + bytecode, }, { profile: foundryProfile }, ).catch((error) => { @@ -47,14 +47,14 @@ export async function verify({ ...Object.entries(getWorldFactoryContracts(deployer)).map( ([name, { bytecode }]) => () => - verifyContractCreate2( + verifyContract( { name, - from: deployer, - bytecode, rpc, verifier, verifierUrl, + from: deployer, + bytecode, }, { profile: foundryProfile, @@ -67,14 +67,14 @@ export async function verify({ ...modules.map( ({ name, bytecode }) => () => - verifyContractCreate2( + verifyContract( { name: name, - from: deployer, - bytecode: bytecode, rpc, verifier, verifierUrl, + from: deployer, + bytecode, }, { profile: foundryProfile, @@ -86,7 +86,7 @@ export async function verify({ ), () => verifyContract( - { name: "World", address: worldAddress, rpc, verifier, verifierUrl }, + { name: "World", rpc, verifier, verifierUrl, address: worldAddress }, { profile: foundryProfile, cwd: "node_modules/@latticexyz/world", diff --git a/packages/cli/src/verifyContract.ts b/packages/cli/src/verifyContract.ts index a7fc655d3d..f700495fd4 100644 --- a/packages/cli/src/verifyContract.ts +++ b/packages/cli/src/verifyContract.ts @@ -1,43 +1,41 @@ import { forge } from "@latticexyz/common/foundry"; import { Address, ByteArray, Hex, getCreate2Address } from "viem"; -import { salt as defaultSalt } from "./deploy/common"; +import { salt } from "./deploy/common"; -type VerificationOptions = { - address: Hex; +type Create2Options = { + bytecode: ByteArray | Hex; + from: Address; +}; + +type VerifyContractOptions = { name: string; rpc: string; verifier?: string; verifierUrl?: string; -}; +} & ({ address: Hex } | Create2Options); type ForgeOptions = { profile?: string; silent?: boolean; env?: NodeJS.ProcessEnv; cwd?: string }; -type Create2Options = { - bytecode: ByteArray | Hex; - from: Address; - salt?: ByteArray | Hex; -}; - -export async function verifyContract( - { address, name, rpc, verifier, verifierUrl }: VerificationOptions, - options?: ForgeOptions, -) { - const args = ["verify-contract", address, name, "--rpc-url", rpc]; +export async function verifyContract(options: VerifyContractOptions, forgeOptions?: ForgeOptions) { + const args = [ + "verify-contract", + "address" in options + ? options.address + : getCreate2Address({ + from: options.from, + bytecode: options.bytecode, + salt, + }), + options.name, + "--rpc-url", + options.rpc, + ]; - if (verifier) { - args.push("--verifier", verifier); + if (options.verifier) { + args.push("--verifier", options.verifier); } - if (verifierUrl) { - args.push("--verifier-url", verifierUrl); + if (options.verifierUrl) { + args.push("--verifier-url", options.verifierUrl); } - await forge(args, options); -} - -export async function verifyContractCreate2( - { name, rpc, verifier, verifierUrl, from, bytecode, salt }: Omit & Create2Options, - options?: ForgeOptions, -) { - const address = getCreate2Address({ from, bytecode, salt: salt !== undefined ? salt : defaultSalt }); - - return verifyContract({ address, name, rpc, verifier, verifierUrl }, options); + await forge(args, forgeOptions); } From 0f8147d2b35a8571283cb78b1d63ebc0f2a03c3e Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 18 Apr 2024 17:33:08 +0100 Subject: [PATCH 45/62] refactor --- packages/cli/src/verifyContract.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/verifyContract.ts b/packages/cli/src/verifyContract.ts index f700495fd4..ca745c2e9a 100644 --- a/packages/cli/src/verifyContract.ts +++ b/packages/cli/src/verifyContract.ts @@ -17,19 +17,16 @@ type VerifyContractOptions = { type ForgeOptions = { profile?: string; silent?: boolean; env?: NodeJS.ProcessEnv; cwd?: string }; export async function verifyContract(options: VerifyContractOptions, forgeOptions?: ForgeOptions) { - const args = [ - "verify-contract", + const address = "address" in options ? options.address : getCreate2Address({ from: options.from, bytecode: options.bytecode, salt, - }), - options.name, - "--rpc-url", - options.rpc, - ]; + }); + + const args = ["verify-contract", address, options.name, "--rpc-url", options.rpc]; if (options.verifier) { args.push("--verifier", options.verifier); From c7e2ae564cc772aa577fd0a10ce1d9757fa3cf3e Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 12:50:03 +0100 Subject: [PATCH 46/62] refactor: map to add tasks --- packages/cli/src/verify.ts | 127 +++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 63 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index eade8a5d00..7bac83b80a 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -29,75 +29,76 @@ export async function verify({ const verifyQueue = new PQueue({ concurrency: 1 }); - const tasks = [ - ...systems.map( - ({ name, bytecode }) => - () => - verifyContract( - { - name, - rpc, - verifier, - verifierUrl, - from: deployer, - bytecode, - }, - { profile: foundryProfile }, - ).catch((error) => { - console.error(`Error verifying system contract ${name}:`, error); - }), - ), - ...Object.entries(useProxy ? getWorldProxyFactoryContracts(deployer) : getWorldFactoryContracts(deployer)).map( - ([name, { bytecode }]) => - () => - verifyContract( - { - name, - rpc, - verifier, - verifierUrl, - from: deployer, - bytecode, - }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }, - ).catch((error) => { - console.error(`Error verifying world factory contract ${name}:`, error); - }), - ), - ...modules.map( - ({ name, bytecode }) => - () => - verifyContract( - { - name: name, - rpc, - verifier, - verifierUrl, - from: deployer, - bytecode, - }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world-modules", - }, - ).catch((error) => { - console.error(`Error verifying module contract ${name}:`, error); - }), + systems.map(({ name, bytecode }) => + verifyQueue.add(() => + verifyContract( + { + name, + rpc, + verifier, + verifierUrl, + from: deployer, + bytecode, + }, + { profile: foundryProfile }, + ).catch((error) => { + console.error(`Error verifying system contract ${name}:`, error); + }), ), - () => + ); + + Object.entries(useProxy ? getWorldProxyFactoryContracts(deployer) : getWorldFactoryContracts(deployer)).map( + ([name, { bytecode }]) => + verifyQueue.add(() => + verifyContract( + { + name, + rpc, + verifier, + verifierUrl, + from: deployer, + bytecode, + }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ).catch((error) => { + console.error(`Error verifying world factory contract ${name}:`, error); + }), + ), + ); + + modules.map(({ name, bytecode }) => + verifyQueue.add(() => verifyContract( - { name: "World", rpc, verifier, verifierUrl, address: worldAddress }, + { + name: name, + rpc, + verifier, + verifierUrl, + from: deployer, + bytecode, + }, { profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", + cwd: "node_modules/@latticexyz/world-modules", }, ).catch((error) => { - console.error(`Error verifying World contract:`, error); + console.error(`Error verifying module contract ${name}:`, error); }), - ]; + ), + ); - tasks.forEach((task) => verifyQueue.add(task)); + verifyQueue.add(() => + verifyContract( + { name: "World", rpc, verifier, verifierUrl, address: worldAddress }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ).catch((error) => { + console.error(`Error verifying World contract:`, error); + }), + ); } From e84d7cc72d1ffbc4cae0723f1d34b43a7dab1de9 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 14:33:55 +0100 Subject: [PATCH 47/62] gm --- packages/cli/src/verify.ts | 57 +++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 7bac83b80a..bef03bb722 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,10 +1,10 @@ import { getRpcUrl } from "@latticexyz/common/foundry"; import { Hex } from "viem"; -import { deployer } from "./deploy/ensureDeployer"; import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; import { verifyContract } from "./verifyContract"; import PQueue from "p-queue"; import { getWorldProxyFactoryContracts } from "./deploy/getWorldProxyFactoryContracts"; +import { deployer } from "./deploy/ensureDeployer"; type VerifyOptions = { foundryProfile?: string; @@ -13,6 +13,13 @@ type VerifyOptions = { systems: { name: string; bytecode: Hex }[]; modules: { name: string; bytecode: Hex }[]; worldAddress: Hex; + /** + * Address of determinstic deployment proxy: https://github.com/Arachnid/deterministic-deployment-proxy + * By default, we look for a deployment at 0x4e59b44847b379578588920ca78fbf26c0b4956c and, if not, deploy one. + * If the target chain does not support legacy transactions, we deploy the proxy bytecode anyway, but it will + * not have a deterministic address. + */ + deployerAddress?: Hex; useProxy?: boolean; }; @@ -21,10 +28,13 @@ export async function verify({ systems, modules, worldAddress, + deployerAddress: initialDeployerAddress, verifier, verifierUrl, useProxy, }: VerifyOptions): Promise { + const deployerAddress = initialDeployerAddress ?? deployer; + const rpc = await getRpcUrl(foundryProfile); const verifyQueue = new PQueue({ concurrency: 1 }); @@ -37,7 +47,7 @@ export async function verify({ rpc, verifier, verifierUrl, - from: deployer, + from: deployerAddress, bytecode, }, { profile: foundryProfile }, @@ -47,26 +57,27 @@ export async function verify({ ), ); - Object.entries(useProxy ? getWorldProxyFactoryContracts(deployer) : getWorldFactoryContracts(deployer)).map( - ([name, { bytecode }]) => - verifyQueue.add(() => - verifyContract( - { - name, - rpc, - verifier, - verifierUrl, - from: deployer, - bytecode, - }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }, - ).catch((error) => { - console.error(`Error verifying world factory contract ${name}:`, error); - }), - ), + Object.entries( + useProxy ? getWorldProxyFactoryContracts(deployerAddress) : getWorldFactoryContracts(deployerAddress), + ).map(([name, { bytecode }]) => + verifyQueue.add(() => + verifyContract( + { + name, + rpc, + verifier, + verifierUrl, + from: deployerAddress, + bytecode, + }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ).catch((error) => { + console.error(`Error verifying world factory contract ${name}:`, error); + }), + ), ); modules.map(({ name, bytecode }) => @@ -77,7 +88,7 @@ export async function verify({ rpc, verifier, verifierUrl, - from: deployer, + from: deployerAddress, bytecode, }, { From 2ecfec4fb662c55c1396e19723a36558404945ea Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 14:40:30 +0100 Subject: [PATCH 48/62] feat: use getDeployer --- packages/cli/src/commands/verify.ts | 68 +++++++++++++++-------- packages/cli/src/deploy/ensureDeployer.ts | 2 +- packages/cli/src/verify.ts | 12 +++- 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 9584142a9c..47e541ae9e 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -1,17 +1,18 @@ import type { CommandModule } from "yargs"; import { verify } from "../verify"; -import { logError } from "../utils/errors"; import { loadConfig } from "@latticexyz/config/node"; import { World as WorldConfig } from "@latticexyz/world"; import { resolveWorldConfig } from "@latticexyz/world/internal"; import { worldToV1 } from "@latticexyz/world/config/v2"; -import { getOutDirectory, getSrcDirectory } from "@latticexyz/common/foundry"; +import { getOutDirectory, getRpcUrl, getSrcDirectory } from "@latticexyz/common/foundry"; import { getExistingContracts } from "../utils/getExistingContracts"; import { getContractData } from "../utils/getContractData"; import { defaultModuleContracts } from "../utils/defaultModuleContracts"; -import { Hex } from "viem"; +import { Hex, createWalletClient, http } from "viem"; +import chalk from "chalk"; type Options = { + deployerAddress?: string; worldAddress: string; configPath?: string; profile?: string; @@ -28,9 +29,18 @@ const commandModule: CommandModule = { builder(yargs) { return yargs.options({ + deployerAddress: { + type: "string", + desc: "Deploy using an existing deterministic deployer (https://github.com/Arachnid/deterministic-deployment-proxy)", + }, worldAddress: { type: "string", required: true, desc: "Verify an existing World at the given address" }, configPath: { type: "string", desc: "Path to the MUD config file" }, profile: { type: "string", desc: "The foundry profile to use" }, + rpc: { type: "string", desc: "The RPC URL to use. Defaults to the RPC url from the local foundry.toml" }, + rpcBatch: { + type: "boolean", + desc: "Enable batch processing of RPC requests in viem client (defaults to batch size of 100 and wait of 1s)", + }, srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." }, verifier: { type: "string", desc: "The verifier to use" }, verifierUrl: { @@ -47,16 +57,32 @@ const commandModule: CommandModule = { async handler(opts) { const profile = opts.profile ?? process.env.FOUNDRY_PROFILE; - const config = (await loadConfig(opts.configPath)) as WorldConfig; - - // Get user-defined systems - const configV1 = worldToV1(config); + const configV2 = (await loadConfig(opts.configPath)) as WorldConfig; + const config = worldToV1(configV2); const srcDir = opts.srcDir ?? (await getSrcDirectory(profile)); const outDir = await getOutDirectory(profile); + const rpc = opts.rpc ?? (await getRpcUrl(profile)); + console.log( + chalk.bgBlue( + chalk.whiteBright(`\n Verifying MUD contracts${profile ? " with profile " + profile : ""} to RPC ${rpc} \n`), + ), + ); + + const client = createWalletClient({ + transport: http(rpc, { + batch: opts.rpcBatch + ? { + batchSize: 100, + wait: 1000, + } + : undefined, + }), + }); + const contractNames = getExistingContracts(srcDir).map(({ basename }) => basename); - const resolvedWorldConfig = resolveWorldConfig(configV1, contractNames); + const resolvedWorldConfig = resolveWorldConfig(config, contractNames); const systems = Object.keys(resolvedWorldConfig.systems).map((name) => { const contractData = getContractData(`${name}.sol`, name, outDir); @@ -79,21 +105,17 @@ const commandModule: CommandModule = { }; }); - // Wrap in try/catch, because yargs seems to swallow errors - try { - await verify({ - foundryProfile: profile, - systems, - modules, - worldAddress: opts.worldAddress as Hex, - verifier: opts.verifier, - verifierUrl: opts.verifierUrl, - useProxy: opts.useProxy, - }); - } catch (error) { - logError(error); - process.exit(1); - } + await verify({ + client, + foundryProfile: profile, + systems, + modules, + deployerAddress: opts.deployerAddress as Hex | undefined, + worldAddress: opts.worldAddress as Hex, + verifier: opts.verifier, + verifierUrl: opts.verifierUrl, + useProxy: opts.useProxy, + }); }, }; diff --git a/packages/cli/src/deploy/ensureDeployer.ts b/packages/cli/src/deploy/ensureDeployer.ts index 5990d401f7..fca96d0a04 100644 --- a/packages/cli/src/deploy/ensureDeployer.ts +++ b/packages/cli/src/deploy/ensureDeployer.ts @@ -4,7 +4,7 @@ import deployment from "./create2/deployment.json"; import { debug } from "./debug"; import { getDeployer } from "./getDeployer"; -export const deployer = `0x${deployment.address}` as const; +const deployer = `0x${deployment.address}` as const; export async function ensureDeployer(client: Client): Promise
{ const existingDeployer = await getDeployer(client); diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index bef03bb722..0dd9732ee4 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,12 +1,14 @@ import { getRpcUrl } from "@latticexyz/common/foundry"; -import { Hex } from "viem"; +import { Chain, Client, Hex, Transport } from "viem"; import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; import { verifyContract } from "./verifyContract"; import PQueue from "p-queue"; import { getWorldProxyFactoryContracts } from "./deploy/getWorldProxyFactoryContracts"; -import { deployer } from "./deploy/ensureDeployer"; +import { getDeployer } from "./deploy/getDeployer"; +import { MUDError } from "@latticexyz/common/errors"; type VerifyOptions = { + client: Client; foundryProfile?: string; verifier?: string; verifierUrl?: string; @@ -24,6 +26,7 @@ type VerifyOptions = { }; export async function verify({ + client, foundryProfile = process.env.FOUNDRY_PROFILE, systems, modules, @@ -33,7 +36,10 @@ export async function verify({ verifierUrl, useProxy, }: VerifyOptions): Promise { - const deployerAddress = initialDeployerAddress ?? deployer; + const deployerAddress = initialDeployerAddress ?? (await getDeployer(client)); + if (!deployerAddress) { + throw new MUDError(`No deployer`); + } const rpc = await getRpcUrl(foundryProfile); From 7ffb40189f22a954cba70bb626551da87eebf751 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 14:41:30 +0100 Subject: [PATCH 49/62] fix: types --- packages/cli/src/commands/verify.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 47e541ae9e..881ab620c2 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -16,6 +16,8 @@ type Options = { worldAddress: string; configPath?: string; profile?: string; + rpc?: string; + rpcBatch?: boolean; srcDir?: string; verifier?: string; verifierUrl?: string; From 12afd82840dba10be5d52c4e7a4b711e4f5b71ab Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 14:43:31 +0100 Subject: [PATCH 50/62] docs: comment --- packages/cli/src/verify.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 0dd9732ee4..c33d32b764 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -17,9 +17,8 @@ type VerifyOptions = { worldAddress: Hex; /** * Address of determinstic deployment proxy: https://github.com/Arachnid/deterministic-deployment-proxy - * By default, we look for a deployment at 0x4e59b44847b379578588920ca78fbf26c0b4956c and, if not, deploy one. - * If the target chain does not support legacy transactions, we deploy the proxy bytecode anyway, but it will - * not have a deterministic address. + * By default, we look for a deployment at 0x4e59b44847b379578588920ca78fbf26c0b4956c. + * If it is not deployed or the target chain does not support legacy transactions, the user must set the deployer manually. */ deployerAddress?: Hex; useProxy?: boolean; From d613460f7499813ff056c777b22ae5b8855d2de1 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 14:44:51 +0100 Subject: [PATCH 51/62] refactor: rpc --- packages/cli/src/commands/verify.ts | 1 + packages/cli/src/verify.ts | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 881ab620c2..70f4aeeb89 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -109,6 +109,7 @@ const commandModule: CommandModule = { await verify({ client, + rpc, foundryProfile: profile, systems, modules, diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index c33d32b764..d2e377b8e7 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,4 +1,3 @@ -import { getRpcUrl } from "@latticexyz/common/foundry"; import { Chain, Client, Hex, Transport } from "viem"; import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; import { verifyContract } from "./verifyContract"; @@ -9,6 +8,7 @@ import { MUDError } from "@latticexyz/common/errors"; type VerifyOptions = { client: Client; + rpc: string; foundryProfile?: string; verifier?: string; verifierUrl?: string; @@ -26,6 +26,7 @@ type VerifyOptions = { export async function verify({ client, + rpc, foundryProfile = process.env.FOUNDRY_PROFILE, systems, modules, @@ -40,8 +41,6 @@ export async function verify({ throw new MUDError(`No deployer`); } - const rpc = await getRpcUrl(foundryProfile); - const verifyQueue = new PQueue({ concurrency: 1 }); systems.map(({ name, bytecode }) => From dc0411aa454ac1bdef5b84f00277d7cad2bfe4dc Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 19:10:35 +0100 Subject: [PATCH 52/62] refactor: verify folder --- packages/cli/src/verify.ts | 2 +- packages/cli/src/{ => verify}/verifyContract.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename packages/cli/src/{ => verify}/verifyContract.ts (96%) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index d2e377b8e7..0c65ec8ea0 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,6 +1,6 @@ import { Chain, Client, Hex, Transport } from "viem"; import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; -import { verifyContract } from "./verifyContract"; +import { verifyContract } from "./verify/verifyContract"; import PQueue from "p-queue"; import { getWorldProxyFactoryContracts } from "./deploy/getWorldProxyFactoryContracts"; import { getDeployer } from "./deploy/getDeployer"; diff --git a/packages/cli/src/verifyContract.ts b/packages/cli/src/verify/verifyContract.ts similarity index 96% rename from packages/cli/src/verifyContract.ts rename to packages/cli/src/verify/verifyContract.ts index ca745c2e9a..6e80c8b42f 100644 --- a/packages/cli/src/verifyContract.ts +++ b/packages/cli/src/verify/verifyContract.ts @@ -1,6 +1,6 @@ import { forge } from "@latticexyz/common/foundry"; import { Address, ByteArray, Hex, getCreate2Address } from "viem"; -import { salt } from "./deploy/common"; +import { salt } from "../deploy/common"; type Create2Options = { bytecode: ByteArray | Hex; From e90e2216f226e9d68ff377f83ae19e5fb2a1db02 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 19:11:11 +0100 Subject: [PATCH 53/62] refactor: address type --- packages/cli/src/verify/verifyContract.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/verify/verifyContract.ts b/packages/cli/src/verify/verifyContract.ts index 6e80c8b42f..74b8a2d548 100644 --- a/packages/cli/src/verify/verifyContract.ts +++ b/packages/cli/src/verify/verifyContract.ts @@ -12,7 +12,7 @@ type VerifyContractOptions = { rpc: string; verifier?: string; verifierUrl?: string; -} & ({ address: Hex } | Create2Options); +} & ({ address: Address } | Create2Options); type ForgeOptions = { profile?: string; silent?: boolean; env?: NodeJS.ProcessEnv; cwd?: string }; From a2a30be01fde1c7f49c63533684274d8d9b50aae Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 19:33:43 +0100 Subject: [PATCH 54/62] refactor: verify contract takes address --- packages/cli/src/verify.ts | 24 ++++++++++++++++------- packages/cli/src/verify/verifyContract.ts | 20 ++++--------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 0c65ec8ea0..92a14be0e4 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,10 +1,11 @@ -import { Chain, Client, Hex, Transport } from "viem"; +import { Chain, Client, Hex, Transport, getCreate2Address } from "viem"; import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; import { verifyContract } from "./verify/verifyContract"; import PQueue from "p-queue"; import { getWorldProxyFactoryContracts } from "./deploy/getWorldProxyFactoryContracts"; import { getDeployer } from "./deploy/getDeployer"; import { MUDError } from "@latticexyz/common/errors"; +import { salt } from "./deploy/common"; type VerifyOptions = { client: Client; @@ -51,8 +52,11 @@ export async function verify({ rpc, verifier, verifierUrl, - from: deployerAddress, - bytecode, + address: getCreate2Address({ + from: deployerAddress, + bytecode: bytecode, + salt, + }), }, { profile: foundryProfile }, ).catch((error) => { @@ -71,8 +75,11 @@ export async function verify({ rpc, verifier, verifierUrl, - from: deployerAddress, - bytecode, + address: getCreate2Address({ + from: deployerAddress, + bytecode: bytecode, + salt, + }), }, { profile: foundryProfile, @@ -92,8 +99,11 @@ export async function verify({ rpc, verifier, verifierUrl, - from: deployerAddress, - bytecode, + address: getCreate2Address({ + from: deployerAddress, + bytecode: bytecode, + salt, + }), }, { profile: foundryProfile, diff --git a/packages/cli/src/verify/verifyContract.ts b/packages/cli/src/verify/verifyContract.ts index 74b8a2d548..7f5e2b7e32 100644 --- a/packages/cli/src/verify/verifyContract.ts +++ b/packages/cli/src/verify/verifyContract.ts @@ -1,30 +1,18 @@ import { forge } from "@latticexyz/common/foundry"; -import { Address, ByteArray, Hex, getCreate2Address } from "viem"; -import { salt } from "../deploy/common"; - -type Create2Options = { - bytecode: ByteArray | Hex; - from: Address; -}; +import { Address } from "viem"; type VerifyContractOptions = { name: string; rpc: string; verifier?: string; verifierUrl?: string; -} & ({ address: Address } | Create2Options); + address: Address; +}; type ForgeOptions = { profile?: string; silent?: boolean; env?: NodeJS.ProcessEnv; cwd?: string }; export async function verifyContract(options: VerifyContractOptions, forgeOptions?: ForgeOptions) { - const address = - "address" in options - ? options.address - : getCreate2Address({ - from: options.from, - bytecode: options.bytecode, - salt, - }); + const { address } = options; const args = ["verify-contract", address, options.name, "--rpc-url", options.rpc]; From 2f8e0655eacf0de4e6a267659824129116acb965 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 19:33:59 +0100 Subject: [PATCH 55/62] tweak --- packages/cli/src/verify/verifyContract.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/cli/src/verify/verifyContract.ts b/packages/cli/src/verify/verifyContract.ts index 7f5e2b7e32..6f558f240d 100644 --- a/packages/cli/src/verify/verifyContract.ts +++ b/packages/cli/src/verify/verifyContract.ts @@ -12,9 +12,7 @@ type VerifyContractOptions = { type ForgeOptions = { profile?: string; silent?: boolean; env?: NodeJS.ProcessEnv; cwd?: string }; export async function verifyContract(options: VerifyContractOptions, forgeOptions?: ForgeOptions) { - const { address } = options; - - const args = ["verify-contract", address, options.name, "--rpc-url", options.rpc]; + const args = ["verify-contract", options.address, options.name, "--rpc-url", options.rpc]; if (options.verifier) { args.push("--verifier", options.verifier); From 3f9b08bae7f672b7128c6467b19ffdf75ccf7156 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 21:29:15 +0100 Subject: [PATCH 56/62] feat: figure out if proxy --- packages/cli/src/commands/verify.ts | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 70f4aeeb89..c9d7b2fce1 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -8,7 +8,7 @@ import { getOutDirectory, getRpcUrl, getSrcDirectory } from "@latticexyz/common/ import { getExistingContracts } from "../utils/getExistingContracts"; import { getContractData } from "../utils/getContractData"; import { defaultModuleContracts } from "../utils/defaultModuleContracts"; -import { Hex, createWalletClient, http } from "viem"; +import { Address, Hex, createPublicClient, createWalletClient, http, zeroHash } from "viem"; import chalk from "chalk"; type Options = { @@ -21,9 +21,10 @@ type Options = { srcDir?: string; verifier?: string; verifierUrl?: string; - useProxy?: boolean; }; +const ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; + const commandModule: CommandModule = { command: "verify", @@ -49,10 +50,6 @@ const commandModule: CommandModule = { type: "string", desc: "The verification provider.", }, - useProxy: { - type: "boolean", - desc: "Whether the World was deployed with a proxy.", - }, }); }, @@ -83,6 +80,17 @@ const commandModule: CommandModule = { }), }); + const publicClient = createPublicClient({ + transport: http(rpc, { + batch: opts.rpcBatch + ? { + batchSize: 100, + wait: 1000, + } + : undefined, + }), + }); + const contractNames = getExistingContracts(srcDir).map(({ basename }) => basename); const resolvedWorldConfig = resolveWorldConfig(config, contractNames); @@ -107,6 +115,12 @@ const commandModule: CommandModule = { }; }); + const implementation = await publicClient.getStorageAt({ + address: opts.worldAddress as Address, + slot: ERC1967_IMPLEMENTATION_SLOT, + }); + const useProxy = implementation !== zeroHash; + await verify({ client, rpc, @@ -117,7 +131,7 @@ const commandModule: CommandModule = { worldAddress: opts.worldAddress as Hex, verifier: opts.verifier, verifierUrl: opts.verifierUrl, - useProxy: opts.useProxy, + useProxy, }); }, }; From 7ec78cb92807e49c1c84e017c320d4e62090e9c4 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 21:42:21 +0100 Subject: [PATCH 57/62] docs: add comment on proxy --- packages/cli/src/commands/verify.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index c9d7b2fce1..9948431082 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -115,11 +115,12 @@ const commandModule: CommandModule = { }; }); - const implementation = await publicClient.getStorageAt({ + // If the proxy implementation storage slot is set on the World, the World was deployed as a proxy. + const proxyImplementation = await publicClient.getStorageAt({ address: opts.worldAddress as Address, slot: ERC1967_IMPLEMENTATION_SLOT, }); - const useProxy = implementation !== zeroHash; + const useProxy = proxyImplementation !== zeroHash; await verify({ client, From 1eba1038fa8b3683defb6c321f01da38a5de0c43 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Wed, 24 Apr 2024 21:47:25 +0100 Subject: [PATCH 58/62] refactor: infer types --- packages/cli/src/commands/verify.ts | 56 +++++++++++++---------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 9948431082..6eb6be9e62 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -1,4 +1,4 @@ -import type { CommandModule } from "yargs"; +import type { CommandModule, InferredOptionTypes } from "yargs"; import { verify } from "../verify"; import { loadConfig } from "@latticexyz/config/node"; import { World as WorldConfig } from "@latticexyz/world"; @@ -11,17 +11,28 @@ import { defaultModuleContracts } from "../utils/defaultModuleContracts"; import { Address, Hex, createPublicClient, createWalletClient, http, zeroHash } from "viem"; import chalk from "chalk"; -type Options = { - deployerAddress?: string; - worldAddress: string; - configPath?: string; - profile?: string; - rpc?: string; - rpcBatch?: boolean; - srcDir?: string; - verifier?: string; - verifierUrl?: string; -}; +const verifyOptions = { + deployerAddress: { + type: "string", + desc: "Deploy using an existing deterministic deployer (https://github.com/Arachnid/deterministic-deployment-proxy)", + }, + worldAddress: { type: "string", required: true, desc: "Verify an existing World at the given address" }, + configPath: { type: "string", desc: "Path to the MUD config file" }, + profile: { type: "string", desc: "The foundry profile to use" }, + rpc: { type: "string", desc: "The RPC URL to use. Defaults to the RPC url from the local foundry.toml" }, + rpcBatch: { + type: "boolean", + desc: "Enable batch processing of RPC requests in viem client (defaults to batch size of 100 and wait of 1s)", + }, + srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." }, + verifier: { type: "string", desc: "The verifier to use" }, + verifierUrl: { + type: "string", + desc: "The verification provider.", + }, +} as const; + +type Options = InferredOptionTypes; const ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; @@ -31,26 +42,7 @@ const commandModule: CommandModule = { describe: "Verify contracts", builder(yargs) { - return yargs.options({ - deployerAddress: { - type: "string", - desc: "Deploy using an existing deterministic deployer (https://github.com/Arachnid/deterministic-deployment-proxy)", - }, - worldAddress: { type: "string", required: true, desc: "Verify an existing World at the given address" }, - configPath: { type: "string", desc: "Path to the MUD config file" }, - profile: { type: "string", desc: "The foundry profile to use" }, - rpc: { type: "string", desc: "The RPC URL to use. Defaults to the RPC url from the local foundry.toml" }, - rpcBatch: { - type: "boolean", - desc: "Enable batch processing of RPC requests in viem client (defaults to batch size of 100 and wait of 1s)", - }, - srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." }, - verifier: { type: "string", desc: "The verifier to use" }, - verifierUrl: { - type: "string", - desc: "The verification provider.", - }, - }); + return yargs.options(verifyOptions); }, async handler(opts) { From 9099bee1ec638a943b16c22b89de8cef2bda86f7 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 25 Apr 2024 11:03:39 +0100 Subject: [PATCH 59/62] fix: world address should be verified as proxy --- packages/cli/src/verify.ts | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 92a14be0e4..7abefd30d9 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -116,14 +116,24 @@ export async function verify({ ); verifyQueue.add(() => - verifyContract( - { name: "World", rpc, verifier, verifierUrl, address: worldAddress }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }, - ).catch((error) => { - console.error(`Error verifying World contract:`, error); - }), + useProxy + ? verifyContract( + { name: "WorldProxy", rpc, verifier, verifierUrl, address: worldAddress }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ).catch((error) => { + console.error(`Error verifying WorldProxy contract:`, error); + }) + : verifyContract( + { name: "World", rpc, verifier, verifierUrl, address: worldAddress }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ).catch((error) => { + console.error(`Error verifying World contract:`, error); + }), ); } From a37f051fcbec08341a8ae2bd185a8262395c5b91 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 25 Apr 2024 11:24:50 +0100 Subject: [PATCH 60/62] fix: proxy verifies proxy and implementation --- packages/cli/src/commands/verify.ts | 23 +-------- packages/cli/src/verify.ts | 77 ++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 45 deletions(-) diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 6eb6be9e62..d0a6b24294 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -8,7 +8,7 @@ import { getOutDirectory, getRpcUrl, getSrcDirectory } from "@latticexyz/common/ import { getExistingContracts } from "../utils/getExistingContracts"; import { getContractData } from "../utils/getContractData"; import { defaultModuleContracts } from "../utils/defaultModuleContracts"; -import { Address, Hex, createPublicClient, createWalletClient, http, zeroHash } from "viem"; +import { Hex, createWalletClient, http } from "viem"; import chalk from "chalk"; const verifyOptions = { @@ -34,8 +34,6 @@ const verifyOptions = { type Options = InferredOptionTypes; -const ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; - const commandModule: CommandModule = { command: "verify", @@ -72,17 +70,6 @@ const commandModule: CommandModule = { }), }); - const publicClient = createPublicClient({ - transport: http(rpc, { - batch: opts.rpcBatch - ? { - batchSize: 100, - wait: 1000, - } - : undefined, - }), - }); - const contractNames = getExistingContracts(srcDir).map(({ basename }) => basename); const resolvedWorldConfig = resolveWorldConfig(config, contractNames); @@ -107,13 +94,6 @@ const commandModule: CommandModule = { }; }); - // If the proxy implementation storage slot is set on the World, the World was deployed as a proxy. - const proxyImplementation = await publicClient.getStorageAt({ - address: opts.worldAddress as Address, - slot: ERC1967_IMPLEMENTATION_SLOT, - }); - const useProxy = proxyImplementation !== zeroHash; - await verify({ client, rpc, @@ -124,7 +104,6 @@ const commandModule: CommandModule = { worldAddress: opts.worldAddress as Hex, verifier: opts.verifier, verifierUrl: opts.verifierUrl, - useProxy, }); }, }; diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 7abefd30d9..3af1f5a08b 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,4 +1,4 @@ -import { Chain, Client, Hex, Transport, getCreate2Address } from "viem"; +import { Chain, Client, Hex, Transport, createPublicClient, getCreate2Address, http, sliceHex, zeroHash } from "viem"; import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; import { verifyContract } from "./verify/verifyContract"; import PQueue from "p-queue"; @@ -25,6 +25,8 @@ type VerifyOptions = { useProxy?: boolean; }; +const ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; + export async function verify({ client, rpc, @@ -35,13 +37,23 @@ export async function verify({ deployerAddress: initialDeployerAddress, verifier, verifierUrl, - useProxy, }: VerifyOptions): Promise { const deployerAddress = initialDeployerAddress ?? (await getDeployer(client)); if (!deployerAddress) { throw new MUDError(`No deployer`); } + const publicClient = createPublicClient({ + transport: http(rpc), + }); + + // If the proxy implementation storage slot is set on the World, the World was deployed as a proxy. + const implementationStorage = await publicClient.getStorageAt({ + address: worldAddress, + slot: ERC1967_IMPLEMENTATION_SLOT, + }); + const useProxy = implementationStorage && implementationStorage !== zeroHash; + const verifyQueue = new PQueue({ concurrency: 1 }); systems.map(({ name, bytecode }) => @@ -115,25 +127,44 @@ export async function verify({ ), ); - verifyQueue.add(() => - useProxy - ? verifyContract( - { name: "WorldProxy", rpc, verifier, verifierUrl, address: worldAddress }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }, - ).catch((error) => { - console.error(`Error verifying WorldProxy contract:`, error); - }) - : verifyContract( - { name: "World", rpc, verifier, verifierUrl, address: worldAddress }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }, - ).catch((error) => { - console.error(`Error verifying World contract:`, error); - }), - ); + // If the world was deployed as a Proxy, verify the proxy and implementation. + if (useProxy) { + const implementationAddress = sliceHex(implementationStorage, -20); + + verifyQueue.add(() => + verifyContract( + { name: "WorldProxy", rpc, verifier, verifierUrl, address: worldAddress }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ).catch((error) => { + console.error(`Error verifying WorldProxy contract:`, error); + }), + ); + + verifyQueue.add(() => + verifyContract( + { name: "World", rpc, verifier, verifierUrl, address: implementationAddress }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ).catch((error) => { + console.error(`Error verifying World contract:`, error); + }), + ); + } else { + verifyQueue.add(() => + verifyContract( + { name: "World", rpc, verifier, verifierUrl, address: worldAddress }, + { + profile: foundryProfile, + cwd: "node_modules/@latticexyz/world", + }, + ).catch((error) => { + console.error(`Error verifying World contract:`, error); + }), + ); + } } From 18e24dcff0eb2398bd50d2d65f14cd6261492ae5 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 25 Apr 2024 11:25:42 +0100 Subject: [PATCH 61/62] chore: remove unused arg --- packages/cli/src/verify.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 3af1f5a08b..07749c537e 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -22,7 +22,6 @@ type VerifyOptions = { * If it is not deployed or the target chain does not support legacy transactions, the user must set the deployer manually. */ deployerAddress?: Hex; - useProxy?: boolean; }; const ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"; From 29b9233784e35ad51083473620ed241035aaad7c Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 25 Apr 2024 11:47:33 +0100 Subject: [PATCH 62/62] refactor: no public client --- packages/cli/src/verify.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index 07749c537e..bc4e796f35 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -1,4 +1,4 @@ -import { Chain, Client, Hex, Transport, createPublicClient, getCreate2Address, http, sliceHex, zeroHash } from "viem"; +import { Chain, Client, Hex, Transport, getCreate2Address, sliceHex, zeroHash } from "viem"; import { getWorldFactoryContracts } from "./deploy/getWorldFactoryContracts"; import { verifyContract } from "./verify/verifyContract"; import PQueue from "p-queue"; @@ -6,6 +6,7 @@ import { getWorldProxyFactoryContracts } from "./deploy/getWorldProxyFactoryCont import { getDeployer } from "./deploy/getDeployer"; import { MUDError } from "@latticexyz/common/errors"; import { salt } from "./deploy/common"; +import { getStorageAt } from "viem/actions"; type VerifyOptions = { client: Client; @@ -42,16 +43,12 @@ export async function verify({ throw new MUDError(`No deployer`); } - const publicClient = createPublicClient({ - transport: http(rpc), - }); - // If the proxy implementation storage slot is set on the World, the World was deployed as a proxy. - const implementationStorage = await publicClient.getStorageAt({ + const implementationStorage = await getStorageAt(client, { address: worldAddress, slot: ERC1967_IMPLEMENTATION_SLOT, }); - const useProxy = implementationStorage && implementationStorage !== zeroHash; + const usesProxy = implementationStorage && implementationStorage !== zeroHash; const verifyQueue = new PQueue({ concurrency: 1 }); @@ -77,7 +74,7 @@ export async function verify({ ); Object.entries( - useProxy ? getWorldProxyFactoryContracts(deployerAddress) : getWorldFactoryContracts(deployerAddress), + usesProxy ? getWorldProxyFactoryContracts(deployerAddress) : getWorldFactoryContracts(deployerAddress), ).map(([name, { bytecode }]) => verifyQueue.add(() => verifyContract( @@ -127,7 +124,7 @@ export async function verify({ ); // If the world was deployed as a Proxy, verify the proxy and implementation. - if (useProxy) { + if (usesProxy) { const implementationAddress = sliceHex(implementationStorage, -20); verifyQueue.add(() =>