diff --git a/contracts/config/stagenet-hoodi.json b/contracts/config/stagenet-hoodi.json index 0dbd84c1..a79ac73a 100644 --- a/contracts/config/stagenet-hoodi.json +++ b/contracts/config/stagenet-hoodi.json @@ -43,16 +43,16 @@ "randaoCommitDelay": 4, "randaoCommitExpiration": 24, "minNumRequiredSignatures": 3, - "startBlock": 1299215, + "startBlock": 1303065, "rewardsMessageOrigin": "0x56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd", - "initialValidatorSetId": 2179, + "initialValidatorSetId": 2186, "initialValidatorHashes": [ "0x07ce4f2cd558f4d4b529a3362b6ff7d616ca0893b53252dc62829b8218ea5c10", "0xaea5344f086d3be7c94cf3a47436bcbb98de23cf1ee773a9180cfecab0453a50", "0xcd3a33755b27fe810dfb780b3f1df1c25efa1bb826ca618e41022fa900876087", "0x4f4ce8cad711a4b33d15095091f8a98eaf9bfd1b39a9159e605cf5d6783cc667" ], - "nextValidatorSetId": 2180, + "nextValidatorSetId": 2187, "nextValidatorHashes": [ "0x07ce4f2cd558f4d4b529a3362b6ff7d616ca0893b53252dc62829b8218ea5c10", "0xaea5344f086d3be7c94cf3a47436bcbb98de23cf1ee773a9180cfecab0453a50", diff --git a/contracts/deployments/stagenet-hoodi-rewards-info.json b/contracts/deployments/stagenet-hoodi-rewards-info.json new file mode 100644 index 00000000..32bba16a --- /dev/null +++ b/contracts/deployments/stagenet-hoodi-rewards-info.json @@ -0,0 +1 @@ +{"RewardsAgent": "0x2E039a88838241d1Ac738cf2e3C5763ba12571e7","RewardsAgentOrigin": "0x56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd"} \ No newline at end of file diff --git a/contracts/deployments/stagenet-hoodi.json b/contracts/deployments/stagenet-hoodi.json new file mode 100644 index 00000000..72b70a20 --- /dev/null +++ b/contracts/deployments/stagenet-hoodi.json @@ -0,0 +1 @@ +{"network": "stagenet-hoodi","BeefyClient": "0xE65dc4eCA2Fd428361076e1f204731224CeB4292","AgentExecutor": "0x35d3FdCB19A246a1763421168dF69dA3dE207063","Gateway": "0xE9352f1488F12bFEd722c133C129ca5F467463d1","ServiceManager": "0xED73cCaF067cebC706B2B3a6cf2b9af2c696c6d3","ServiceManagerImplementation": "0x5E1DA2eE025Dac2F8c391Ac86ebA20bd34c32465","RewardsAgent": "0x2E039a88838241d1Ac738cf2e3C5763ba12571e7","DelegationManager": "0x867837a9722C512e0862d8c2E15b8bE220E8b87d","StrategyManager": "0xeE45e76ddbEDdA2918b8C7E3035cd37Eab3b5D41","AVSDirectory": "0xD58f6844f79eB1fbd9f7091d05f7cb30d3363926","RewardsCoordinator": "0x29e8572678e0c272350aa0b4B8f304E47EBcd5e7","AllocationManager": "0x95a7431400F362F3647a69535C5666cA0133CAA0","PermissionController": "0xdcCF401fD121d8C542E96BC1d0078884422aFAD2"} \ No newline at end of file diff --git a/test/cli/handlers/contracts/update-metadata.ts b/test/cli/handlers/contracts/update-metadata.ts index d6f49cba..5c7e50b2 100644 --- a/test/cli/handlers/contracts/update-metadata.ts +++ b/test/cli/handlers/contracts/update-metadata.ts @@ -1,7 +1,7 @@ import { logger, parseDeploymentsFile, printDivider } from "utils"; import { createPublicClient, createWalletClient, encodeFunctionData, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; -import { getChainDeploymentParams } from "../../../configs/contracts/config"; +import { buildNetworkId, getChainDeploymentParams } from "../../../configs/contracts/config"; import { dataHavenServiceManagerAbi } from "../../../contract-bindings/generated"; /** @@ -10,7 +10,7 @@ import { dataHavenServiceManagerAbi } from "../../../contract-bindings/generated export const updateAVSMetadataURI = async ( chain: string, uri: string, - opts: { execute?: boolean; avsOwnerKey?: string } = {} + opts: { execute?: boolean; avsOwnerKey?: string; environment?: string } = {} ) => { try { const execute = opts.execute ?? false; @@ -22,14 +22,15 @@ export const updateAVSMetadataURI = async ( throw new Error("AVS owner private key is required to execute this transaction"); } - // Get chain configuration + // Get chain configuration using base chain name, and build networkId for deployment file lookup + const networkId = buildNetworkId(chain, opts.environment); const deploymentParams = getChainDeploymentParams(chain); - logger.info(`šŸ«Ž Updating AVS metadata URI on ${chain} chain`); + logger.info(`šŸ«Ž Updating AVS metadata URI on ${networkId}`); logger.info(`Network: ${deploymentParams.network} (Chain ID: ${deploymentParams.chainId})`); logger.info(`RPC URL: ${deploymentParams.rpcUrl}`); logger.info(`New URI: ${uri}`); - const deployments = await parseDeploymentsFile(chain); + const deployments = await parseDeploymentsFile(networkId); const serviceManagerAddress = deployments.ServiceManager; if (!serviceManagerAddress) { diff --git a/test/cli/handlers/contracts/verify.ts b/test/cli/handlers/contracts/verify.ts index 5f369b43..5d6bf98b 100644 --- a/test/cli/handlers/contracts/verify.ts +++ b/test/cli/handlers/contracts/verify.ts @@ -14,8 +14,12 @@ interface ContractToVerify { name: string; address: string; artifactName: string; + /** Path to the contract source file relative to the contracts directory (e.g. "src/Foo.sol" or "lib/snowbridge/contracts/src/Bar.sol") */ + contractPath: string; constructorArgs: string[]; constructorArgTypes: string[]; + /** When true, uses forge's --guess-constructor-args instead of explicit args (useful for proxies with complex init data) */ + guessConstructorArgs?: boolean; } /** @@ -41,11 +45,17 @@ export const verifyContracts = async (options: ContractsVerifyOptions) => { const deployments = await parseDeploymentsFile(networkId); + // Resolve the Gateway implementation address from the ERC1967 proxy storage slot + const chainConfig = CHAIN_CONFIGS[options.chain as keyof typeof CHAIN_CONFIGS]; + const rpcUrl = options.rpcUrl || chainConfig.RPC_URL; + const gatewayImplAddress = await getProxyImplementation(deployments.Gateway, rpcUrl); + const contractsToVerify: ContractToVerify[] = [ { name: "ServiceManager Implementation", address: deployments.ServiceManagerImplementation, artifactName: "DataHavenServiceManager", + contractPath: "src/DataHavenServiceManager.sol", constructorArgs: [ deployments.RewardsCoordinator, deployments.PermissionController, @@ -54,16 +64,41 @@ export const verifyContracts = async (options: ContractsVerifyOptions) => { constructorArgTypes: ["address", "address", "address"] }, { - name: "Gateway", - address: deployments.Gateway, - artifactName: "Gateway", + name: "ServiceManager Proxy", + address: deployments.ServiceManager, + artifactName: "TransparentUpgradeableProxy", + contractPath: + "lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol", constructorArgs: [], - constructorArgTypes: [] + constructorArgTypes: [], + guessConstructorArgs: true + }, + ...(gatewayImplAddress + ? [ + { + name: "Gateway Implementation", + address: gatewayImplAddress, + artifactName: "Gateway", + contractPath: "lib/snowbridge/contracts/src/Gateway.sol", + constructorArgs: [deployments.BeefyClient, deployments.AgentExecutor], + constructorArgTypes: ["address", "address"] + } + ] + : []), + { + name: "Gateway Proxy", + address: deployments.Gateway, + artifactName: "GatewayProxy", + contractPath: "lib/snowbridge/contracts/src/GatewayProxy.sol", + constructorArgs: [], + constructorArgTypes: [], + guessConstructorArgs: true }, { name: "BeefyClient", address: deployments.BeefyClient, artifactName: "BeefyClient", + contractPath: "lib/snowbridge/contracts/src/BeefyClient.sol", constructorArgs: [], constructorArgTypes: [] }, @@ -71,11 +106,18 @@ export const verifyContracts = async (options: ContractsVerifyOptions) => { name: "AgentExecutor", address: deployments.AgentExecutor, artifactName: "AgentExecutor", + contractPath: "lib/snowbridge/contracts/src/AgentExecutor.sol", constructorArgs: [], constructorArgTypes: [] } ]; + if (!gatewayImplAddress) { + logger.warn( + "āš ļø Could not resolve Gateway implementation address from proxy, skipping Gateway implementation verification" + ); + } + try { logger.info("šŸ“‹ Contracts to verify:"); contractsToVerify.forEach((contract) => { @@ -109,17 +151,29 @@ export const verifyContracts = async (options: ContractsVerifyOptions) => { async function verifySingleContract(contract: ContractToVerify, options: ContractsVerifyOptions) { logger.info(`\nšŸ” Verifying ${contract.name} (${contract.address})...`); - const { address, artifactName, constructorArgs: args, constructorArgTypes: types } = contract; + const { + address, + artifactName, + contractPath, + constructorArgs: args, + constructorArgTypes: types, + guessConstructorArgs + } = contract; - const abiEncodedArgs = getEncodedConstructorArgs(args, types); - const constructorArgsStr = abiEncodedArgs ? `--constructor-args ${abiEncodedArgs}` : ""; + let constructorArgsStr: string; + if (guessConstructorArgs) { + constructorArgsStr = "--guess-constructor-args"; + } else { + const abiEncodedArgs = getEncodedConstructorArgs(args, types); + constructorArgsStr = abiEncodedArgs ? `--constructor-args ${abiEncodedArgs}` : ""; + } try { const chainConfig = CHAIN_CONFIGS[options.chain as keyof typeof CHAIN_CONFIGS]; const rpcUrl = options.rpcUrl || chainConfig.RPC_URL; const chainParameter = options.chain === "hoodi" ? "--chain-id 560048" : `--chain ${options.chain}`; - const verifyCommand = `forge verify-contract ${address} src/${artifactName}.sol:${artifactName} --rpc-url ${rpcUrl} ${chainParameter} ${constructorArgsStr} --watch`; + const verifyCommand = `forge verify-contract ${address} ${contractPath}:${artifactName} --rpc-url ${rpcUrl} ${chainParameter} ${constructorArgsStr} --watch`; logger.info(`Running: ${verifyCommand}`); @@ -142,7 +196,7 @@ async function verifySingleContract(contract: ContractToVerify, options: Contrac logger.info(`Check manually at: ${chainConfig.BLOCK_EXPLORER}address/${contract.address}`); logger.info("You can also try running the command manually from the contracts directory:"); const rpcUrl = options.rpcUrl || chainConfig.RPC_URL; - const manualCommand = `forge verify-contract ${contract.address} src/${contract.artifactName}.sol:${contract.artifactName} --rpc-url ${rpcUrl} --chain ${options.chain} ${constructorArgsStr}`; + const manualCommand = `forge verify-contract ${contract.address} ${contract.contractPath}:${contract.artifactName} --rpc-url ${rpcUrl} --chain ${options.chain} ${constructorArgsStr}`; logger.info(`cd ../contracts && ${manualCommand}`); } } diff --git a/test/cli/index.ts b/test/cli/index.ts index a9752657..71ad8781 100644 --- a/test/cli/index.ts +++ b/test/cli/index.ts @@ -360,12 +360,14 @@ contractsCommand if (!chain) { throw new Error("--chain parameter is required"); } - // Build network identifier with environment prefix if specified - const environment = options.environment; - const networkId = environment ? `${environment}-${chain}` : chain; - await updateAVSMetadataURI(networkId, options.uri, { + let environment = options.environment; + if (!environment && command.parent) { + environment = command.parent.getOptionValue("environment"); + } + await updateAVSMetadataURI(chain, options.uri, { execute: options.execute, - avsOwnerKey: options.avsOwnerKey + avsOwnerKey: options.avsOwnerKey, + environment }); });