From fe1f806cd10982c432e907cdf2fee2e59862dc1b Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Mon, 24 Nov 2025 18:17:53 -0500 Subject: [PATCH 1/2] feat: add support for blockscout in VerifyOPCM This commit adds support for blockscout in VerifyOPCM and defaults to blockscout. Etherscan verification can still be used but blockscout is simpler and more reliable on all networks. --- .../scripts/deploy/VerifyOPCM.s.sol | 50 +++++++++++++------ .../scripts/libraries/Config.sol | 29 +++++++++++ 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/packages/contracts-bedrock/scripts/deploy/VerifyOPCM.s.sol b/packages/contracts-bedrock/scripts/deploy/VerifyOPCM.s.sol index 1c6c6237c20..c3213db2fea 100644 --- a/packages/contracts-bedrock/scripts/deploy/VerifyOPCM.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/VerifyOPCM.s.sol @@ -495,20 +495,8 @@ contract VerifyOPCM is Script { // If requested and this is not a blueprint, we also need to check the creation code. if (!_target.blueprint && !_skipConstructorVerification) { - // Use the Etherscan API to get the creation code. - bytes memory actualCreationCode = bytes( - Process.bash( - string.concat( - "curl -s 'https://api.etherscan.io/v2/api?chainid=", - vm.toString(block.chainid), - "&module=contract&action=getcontractcreation&contractaddresses=", - vm.toString(_target.addr), - "&apikey=", - Config.etherscanApiKey(), - "' | jq -r '.result[0].creationBytecode'" - ) - ) - ); + // Get the creation code from the selected block explorer. + bytes memory actualCreationCode = _getCreationCode(_target.addr); // Verify that the artifact bytecode is a prefix of the actual creation code and // extract any remaining bytes so we can verify the constructor arguments. @@ -546,6 +534,40 @@ contract VerifyOPCM is Script { return success; } + /// @notice Gets the creation code for a given contract address from the configured block explorer. + /// @param _addr The address of the contract to get the creation code for. + /// @return The creation code of the contract. + function _getCreationCode(address _addr) internal returns (bytes memory) { + // Prepare the command to execute. + string memory cmd; + + // Check which block explorer to use. + if (LibString.eq(Config.blockExplorer(), "blockscout")) { + console.log(" Fetching creation code from Blockscout..."); + cmd = string.concat( + "curl -s '", + Config.blockscoutApiUrl(), + "/api?module=contract&action=getcontractcreation&contractaddresses=", + vm.toString(_addr), + "' | jq -r '.result[0].creationBytecode'" + ); + } else { + console.log(" Fetching creation code from Etherscan..."); + cmd = string.concat( + "curl -s 'https://api.etherscan.io/v2/api?chainid=", + vm.toString(block.chainid), + "&module=contract&action=getcontractcreation&contractaddresses=", + vm.toString(_addr), + "&apikey=", + Config.etherscanApiKey(), + "' | jq -r '.result[0].creationBytecode'" + ); + } + + // Execute the command. + return bytes(Process.bash(cmd)); + } + /// @notice Checks if V2 dispute games feature is enabled in the dev feature bitmap. /// @param _opcm The OPContractsManager to check. /// @return True if V2 dispute games are enabled. diff --git a/packages/contracts-bedrock/scripts/libraries/Config.sol b/packages/contracts-bedrock/scripts/libraries/Config.sol index 4232b2fae93..03309649a5b 100644 --- a/packages/contracts-bedrock/scripts/libraries/Config.sol +++ b/packages/contracts-bedrock/scripts/libraries/Config.sol @@ -129,6 +129,35 @@ library Config { env_ = vm.envString("ETHERSCAN_API_KEY"); } + /// @notice Returns the block explorer to use for fetching creation code. + function blockExplorer() internal view returns (string memory env_) { + env_ = vm.envOr("BLOCK_EXPLORER", string("blockscout")); + } + + /// @notice Returns the base URL for the Blockscout API. + function blockscoutApiUrl() internal view returns (string memory) { + string memory envUrl = vm.envOr("BLOCKSCOUT_API_URL", string("")); + if (bytes(envUrl).length > 0) { + return envUrl; + } + + if (block.chainid == 1) { // Ethereum + return "https://eth.blockscout.com"; + } else if (block.chainid == 10) { // OP Mainnet + return "https://explorer.optimism.io"; + } else if (block.chainid == 11155111) { // Sepolia + return "https://eth-sepolia.blockscout.com"; + } else if (block.chainid == 8453) { // Base + return "https://base.blockscout.com"; + } else if (block.chainid == 84532) { // Base Sepolia + return "https://base-sepolia.blockscout.com"; + } else if (block.chainid == 11155420) { // OP Sepolia + return "https://optimism-sepolia.blockscout.com"; + } else { + return ""; + } + } + /// @notice Returns the OutputMode for genesis allocs generation. /// It reads the mode from the environment variable OUTPUT_MODE. /// If it is unset, OutputMode.ALL is returned. From 944f76bb6b4f173db21848f97fed874bbfeb254b Mon Sep 17 00:00:00 2001 From: Kelvin Fichter Date: Mon, 24 Nov 2025 18:34:48 -0500 Subject: [PATCH 2/2] fix: formatting --- .../scripts/libraries/Config.sol | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/contracts-bedrock/scripts/libraries/Config.sol b/packages/contracts-bedrock/scripts/libraries/Config.sol index 03309649a5b..f388b5d5144 100644 --- a/packages/contracts-bedrock/scripts/libraries/Config.sol +++ b/packages/contracts-bedrock/scripts/libraries/Config.sol @@ -141,17 +141,23 @@ library Config { return envUrl; } - if (block.chainid == 1) { // Ethereum + if (block.chainid == 1) { + // Ethereum return "https://eth.blockscout.com"; - } else if (block.chainid == 10) { // OP Mainnet + } else if (block.chainid == 10) { + // OP Mainnet return "https://explorer.optimism.io"; - } else if (block.chainid == 11155111) { // Sepolia + } else if (block.chainid == 11155111) { + // Sepolia return "https://eth-sepolia.blockscout.com"; - } else if (block.chainid == 8453) { // Base + } else if (block.chainid == 8453) { + // Base return "https://base.blockscout.com"; - } else if (block.chainid == 84532) { // Base Sepolia + } else if (block.chainid == 84532) { + // Base Sepolia return "https://base-sepolia.blockscout.com"; - } else if (block.chainid == 11155420) { // OP Sepolia + } else if (block.chainid == 11155420) { + // OP Sepolia return "https://optimism-sepolia.blockscout.com"; } else { return "";