From b4eb795ee5a6f8d250d3b3513fe72c5530f69c43 Mon Sep 17 00:00:00 2001 From: yonada Date: Sat, 27 Apr 2024 16:02:26 +0100 Subject: [PATCH] fix(cli): fix verify with sourcify for dependencies (#2750) --- .changeset/sour-otters-warn.md | 5 + packages/cli/src/commands/verify.ts | 3 +- packages/cli/src/verify.ts | 172 ++++++++++++---------- packages/cli/src/verify/verifyContract.ts | 7 +- packages/schema-type/.npmignore | 8 +- packages/store/.npmignore | 2 + packages/world-modules/.npmignore | 2 + packages/world/.npmignore | 2 + 8 files changed, 113 insertions(+), 88 deletions(-) create mode 100644 .changeset/sour-otters-warn.md diff --git a/.changeset/sour-otters-warn.md b/.changeset/sour-otters-warn.md new file mode 100644 index 0000000000..f1adaa4463 --- /dev/null +++ b/.changeset/sour-otters-warn.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/cli": patch +--- + +Patched `mud verify` to properly verify store, world, and world-modules contracts. Currently only `sourcify` is fully supported and is the default verifier. diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index d0a6b24294..6dc1478cb3 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -25,7 +25,7 @@ const verifyOptions = { 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" }, + verifier: { type: "string", desc: "The verifier to use. Default to sourcify", default: "sourcify" }, verifierUrl: { type: "string", desc: "The verification provider.", @@ -97,7 +97,6 @@ const commandModule: CommandModule = { await verify({ client, rpc, - foundryProfile: profile, systems, modules, deployerAddress: opts.deployerAddress as Hex | undefined, diff --git a/packages/cli/src/verify.ts b/packages/cli/src/verify.ts index bc4e796f35..7c18b507cd 100644 --- a/packages/cli/src/verify.ts +++ b/packages/cli/src/verify.ts @@ -7,12 +7,12 @@ import { getDeployer } from "./deploy/getDeployer"; import { MUDError } from "@latticexyz/common/errors"; import { salt } from "./deploy/common"; import { getStorageAt } from "viem/actions"; +import { execa } from "execa"; type VerifyOptions = { client: Client; rpc: string; - foundryProfile?: string; - verifier?: string; + verifier: string; verifierUrl?: string; systems: { name: string; bytecode: Hex }[]; modules: { name: string; bytecode: Hex }[]; @@ -30,7 +30,6 @@ const ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076c export async function verify({ client, rpc, - foundryProfile = process.env.FOUNDRY_PROFILE, systems, modules, worldAddress, @@ -50,35 +49,46 @@ export async function verify({ }); const usesProxy = implementationStorage && implementationStorage !== zeroHash; - const verifyQueue = new PQueue({ concurrency: 1 }); + const verifyQueue = new PQueue({ concurrency: 4 }); systems.map(({ name, bytecode }) => verifyQueue.add(() => - verifyContract( - { - name, - rpc, - verifier, - verifierUrl, - address: getCreate2Address({ - from: deployerAddress, - bytecode: bytecode, - salt, - }), - }, - { profile: foundryProfile }, - ).catch((error) => { + verifyContract({ + name, + rpc, + verifier, + verifierUrl, + address: getCreate2Address({ + from: deployerAddress, + bytecode: bytecode, + salt, + }), + }).catch((error) => { console.error(`Error verifying system contract ${name}:`, error); }), ), ); - Object.entries( - usesProxy ? getWorldProxyFactoryContracts(deployerAddress) : getWorldFactoryContracts(deployerAddress), - ).map(([name, { bytecode }]) => - verifyQueue.add(() => - verifyContract( - { + // If the verifier is Sourcify, attempt to verify MUD core contracts + // There are path issues with verifying Blockscout and Etherscan + if (verifier === "sourcify") { + // Install subdependencies so contracts can compile + await execa("npm", ["install"], { + cwd: "node_modules/@latticexyz/store", + }); + await execa("npm", ["install"], { + cwd: "node_modules/@latticexyz/world", + }); + await execa("npm", ["install"], { + cwd: "node_modules/@latticexyz/world-modules", + }); + + Object.entries( + usesProxy ? getWorldProxyFactoryContracts(deployerAddress) : getWorldFactoryContracts(deployerAddress), + ).map(([name, { bytecode }]) => + verifyQueue.add(() => + verifyContract({ + cwd: "node_modules/@latticexyz/world", name, rpc, verifier, @@ -88,21 +98,16 @@ export async function verify({ bytecode: bytecode, salt, }), - }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world", - }, - ).catch((error) => { - console.error(`Error verifying world factory contract ${name}:`, error); - }), - ), - ); + }).catch((error) => { + console.error(`Error verifying world factory contract ${name}:`, error); + }), + ), + ); - modules.map(({ name, bytecode }) => - verifyQueue.add(() => - verifyContract( - { + modules.map(({ name, bytecode }) => + verifyQueue.add(() => + verifyContract({ + cwd: "node_modules/@latticexyz/world-modules", name: name, rpc, verifier, @@ -112,55 +117,60 @@ export async function verify({ bytecode: bytecode, salt, }), - }, - { - profile: foundryProfile, - cwd: "node_modules/@latticexyz/world-modules", - }, - ).catch((error) => { - console.error(`Error verifying module contract ${name}:`, error); - }), - ), - ); + }).catch((error) => { + console.error(`Error verifying module contract ${name}:`, error); + }), + ), + ); - // If the world was deployed as a Proxy, verify the proxy and implementation. - if (usesProxy) { - const implementationAddress = sliceHex(implementationStorage, -20); + // If the world was deployed as a Proxy, verify the proxy and implementation. + if (usesProxy) { + const implementationAddress = sliceHex(implementationStorage, -20); - verifyQueue.add(() => - verifyContract( - { name: "WorldProxy", rpc, verifier, verifierUrl, address: worldAddress }, - { - profile: foundryProfile, + verifyQueue.add(() => + verifyContract({ cwd: "node_modules/@latticexyz/world", - }, - ).catch((error) => { - console.error(`Error verifying WorldProxy contract:`, error); - }), - ); + name: "WorldProxy", + rpc, + verifier, + verifierUrl, + address: worldAddress, + }).catch((error) => { + console.error(`Error verifying WorldProxy contract:`, error); + }), + ); - verifyQueue.add(() => - verifyContract( - { name: "World", rpc, verifier, verifierUrl, address: implementationAddress }, - { - profile: foundryProfile, + verifyQueue.add(() => + verifyContract({ 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, + name: "World", + rpc, + verifier, + verifierUrl, + address: implementationAddress, + }).catch((error) => { + console.error(`Error verifying World contract:`, error); + }), + ); + } else { + verifyQueue.add(() => + verifyContract({ cwd: "node_modules/@latticexyz/world", - }, - ).catch((error) => { - console.error(`Error verifying World contract:`, error); - }), + name: "World", + rpc, + verifier, + verifierUrl, + address: worldAddress, + }).catch((error) => { + console.error(`Error verifying World contract:`, error); + }), + ); + } + } else { + console.log(""); + console.log( + `Note: MUD is currently unable to verify store, world, and world-modules contracts with ${verifier}. We are planning to expand support in a future version.`, ); + console.log(""); } } diff --git a/packages/cli/src/verify/verifyContract.ts b/packages/cli/src/verify/verifyContract.ts index 6f558f240d..44e87629cf 100644 --- a/packages/cli/src/verify/verifyContract.ts +++ b/packages/cli/src/verify/verifyContract.ts @@ -7,11 +7,10 @@ type VerifyContractOptions = { verifier?: string; verifierUrl?: string; address: Address; + cwd?: string; }; -type ForgeOptions = { profile?: string; silent?: boolean; env?: NodeJS.ProcessEnv; cwd?: string }; - -export async function verifyContract(options: VerifyContractOptions, forgeOptions?: ForgeOptions) { +export async function verifyContract(options: VerifyContractOptions) { const args = ["verify-contract", options.address, options.name, "--rpc-url", options.rpc]; if (options.verifier) { @@ -20,5 +19,5 @@ export async function verifyContract(options: VerifyContractOptions, forgeOption if (options.verifierUrl) { args.push("--verifier-url", options.verifierUrl); } - await forge(args, forgeOptions); + await forge(args, { cwd: options.cwd }); } diff --git a/packages/schema-type/.npmignore b/packages/schema-type/.npmignore index eb5910442f..1e9f5aa0ae 100644 --- a/packages/schema-type/.npmignore +++ b/packages/schema-type/.npmignore @@ -3,4 +3,10 @@ !dist/** !src/** !package.json -!README.md \ No newline at end of file +!README.md + +!out/**/*.json +!out/**/*.abi.json +!out/**/*.abi.json.d.ts +!cache/solidity-files-cache.json +!foundry.toml diff --git a/packages/store/.npmignore b/packages/store/.npmignore index 9259405fa5..b56780378c 100644 --- a/packages/store/.npmignore +++ b/packages/store/.npmignore @@ -3,6 +3,8 @@ !out/**/*.json !out/**/*.abi.json !out/**/*.abi.json.d.ts +!cache/solidity-files-cache.json +!foundry.toml !src/** !ts/** !mud.config.ts diff --git a/packages/world-modules/.npmignore b/packages/world-modules/.npmignore index bf5a89e600..6ee4a7e308 100644 --- a/packages/world-modules/.npmignore +++ b/packages/world-modules/.npmignore @@ -3,6 +3,8 @@ !out/**/*.json !out/**/*.abi.json !out/**/*.abi.json.d.ts +!cache/solidity-files-cache.json +!foundry.toml !src/** !ts/** !package.json diff --git a/packages/world/.npmignore b/packages/world/.npmignore index 8d0269c6e7..688be469c8 100644 --- a/packages/world/.npmignore +++ b/packages/world/.npmignore @@ -3,6 +3,8 @@ !out/**/*.json !out/**/*.abi.json !out/**/*.abi.json.d.ts +!cache/solidity-files-cache.json +!foundry.toml !src/** !test/MudTest.t.sol !ts/**