From ac9a28e8576cee3035467d9f06f1bd74318be321 Mon Sep 17 00:00:00 2001 From: philippWOOF Date: Thu, 16 Oct 2025 13:13:58 +0300 Subject: [PATCH 01/11] chore: set configs, key developer and auditor --- contracts/VersionController.sol | 6 +- scripts/config/networkConfig.ts | 118 ++++++++++++++------------------ scripts/deployL1.ts | 31 +++++---- scripts/deployL2.ts | 35 +++++++--- 4 files changed, 101 insertions(+), 89 deletions(-) diff --git a/contracts/VersionController.sol b/contracts/VersionController.sol index 70803a7..ab7b8e9 100644 --- a/contracts/VersionController.sol +++ b/contracts/VersionController.sol @@ -103,12 +103,12 @@ contract VersionController is _disableInitializers(); } - function initialize(address _governor, address _guardian) external initializer { - if (_governor == address(0) || _guardian == address(0)) revert ZeroAddress(); + function initialize(address _initialAdmin, address _guardian) external initializer { + if (_initialAdmin == address(0) || _guardian == address(0)) revert ZeroAddress(); __AccessControlEnumerable_init(); __UUPSUpgradeable_init(); __EIP712_init("VersionController", "1"); - _grantRole(DEFAULT_ADMIN_ROLE, _governor); + _grantRole(DEFAULT_ADMIN_ROLE, _initialAdmin); _grantRole(GUARDIAN_ROLE, _guardian); } diff --git a/scripts/config/networkConfig.ts b/scripts/config/networkConfig.ts index 449988f..7b516d2 100644 --- a/scripts/config/networkConfig.ts +++ b/scripts/config/networkConfig.ts @@ -14,19 +14,20 @@ export interface NetworkConfig { name: string; chainId: number; ccipRouter: string; + sourceChainSelector: string; // CCIP chain selector for this L2 chain timelock: string; cometProxyAdmin: string; assetListFactory: string; l1DeployManager: string; - isTestnet?: boolean; } export const NETWORK_CONFIGS: Record = { - // Ethereum L2s + // Ethereum L2s - Mainnet arbitrum: { name: "arbitrum", chainId: 42161, ccipRouter: "0x141fa059441e0ca23ce184b6a78ba4b7c0a30fb0", + sourceChainSelector: "4949039107694359620", // Arbitrum One CCIP chain selector timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Arbitrum Timelock cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual @@ -38,6 +39,7 @@ export const NETWORK_CONFIGS: Record = { name: "optimism", chainId: 10, ccipRouter: "0x3c3d92629a02a8d95d5cb9650fe49c3544f69b43", + sourceChainSelector: "3734403246176062136", // OP Mainnet CCIP chain selector timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Optimism Timelock cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual @@ -49,6 +51,7 @@ export const NETWORK_CONFIGS: Record = { name: "polygon", chainId: 137, ccipRouter: "0x849c5ed5a80f5b408dd4caa5fe8c2b852aff67a9", + sourceChainSelector: "4051577828743386545", // Polygon CCIP chain selector timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Polygon Timelock cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual @@ -60,67 +63,66 @@ export const NETWORK_CONFIGS: Record = { name: "base", chainId: 8453, ccipRouter: "0x881e3a65b4d4a04dd529061dd0071cf975f58bcd", + sourceChainSelector: "15971525489660198786", // Base CCIP chain selector timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Base Timelock cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual - l1DeployManager: "0x1234567890123456789012345678901234567890", // Will be set from L1 deployment - isTestnet: false + l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, - // Testnets - arbitrumSepolia: { - name: "arbitrumSepolia", - chainId: 421614, - ccipRouter: "0x2a9c5aff799e3ae15fa8306a4c14c0fe4a67ed99", - timelock: "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925", // Test timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Test proxy admin - assetListFactory: "0x1234567890123456789012345678901234567890", // Test asset list factory - l1DeployManager: "0x1234567890123456789012345678901234567890", // Will be set from L1 deployment - isTestnet: true + linea: { + name: "linea", + chainId: 59144, + ccipRouter: "0x549F800f7C8a012C5501C011a85d20baBC51d845", // TODO: Verify actual router address + sourceChainSelector: "4627098889531055414", // Linea CCIP chain selector + timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Linea Timelock + cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, - optimismSepolia: { - name: "optimismSepolia", - chainId: 11155420, - ccipRouter: "0x114a20a10b43d4115e5aeef7345a1a71d2a60c57", - timelock: "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925", // Test timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Test proxy admin - assetListFactory: "0x1234567890123456789012345678901234567890", // Test asset list factory - l1DeployManager: "0x1234567890123456789012345678901234567890", // Will be set from L1 deployment - isTestnet: true + ronin: { + name: "ronin", + chainId: 2020, + ccipRouter: "0x0000000000000000000000000000000000000000", // TODO: Add actual router address + sourceChainSelector: "6916147374840168594", // Ronin CCIP chain selector + timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Ronin Timelock + cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, - polygonAmoy: { - name: "polygonAmoy", - chainId: 80002, - ccipRouter: "0x9c32fcc5de2ce8d30ac582f89b5bd35e8a4b4bc5", - timelock: "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925", // Test timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Test proxy admin - assetListFactory: "0x1234567890123456789012345678901234567890", // Test asset list factory - l1DeployManager: "0x1234567890123456789012345678901234567890", // Will be set from L1 deployment - isTestnet: true + unichain: { + name: "unichain", + chainId: 130, + ccipRouter: "0x0000000000000000000000000000000000000000", // TODO: Add actual router address when available + sourceChainSelector: "0", // TODO: Add actual CCIP chain selector when available + timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Unichain Timelock + cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, - baseSepolia: { - name: "baseSepolia", - chainId: 84532, - ccipRouter: "0xd0daae2231e9cb96b94c8512223533293c3693bf", - timelock: "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925", // Test timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Test proxy admin - assetListFactory: "0x1234567890123456789012345678901234567890", // Test asset list factory - l1DeployManager: "0x1234567890123456789012345678901234567890", // Will be set from L1 deployment - isTestnet: true + mantle: { + name: "mantle", + chainId: 5000, + ccipRouter: "0x0000000000000000000000000000000000000000", // TODO: Verify actual router address + sourceChainSelector: "1556008542357238666", // Mantle CCIP chain selector + timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Mantle Timelock + cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, - avalancheFuji: { - name: "avalancheFuji", - chainId: 43113, - ccipRouter: "0xf694e193200268f9a4868e4aa017a0118c9a8177", - timelock: "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925", // Test timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Test proxy admin - assetListFactory: "0x1234567890123456789012345678901234567890", // Test asset list factory - l1DeployManager: "0x1234567890123456789012345678901234567890", // Will be set from L1 deployment - isTestnet: true + scroll: { + name: "scroll", + chainId: 534352, + ccipRouter: "0x0000000000000000000000000000000000000000", // TODO: Verify actual router address + sourceChainSelector: "13204309965629103672", // Scroll CCIP chain selector + timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Scroll Timelock + cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment } }; @@ -170,22 +172,8 @@ export function setL1DeployManagerAddress(networkName: string, l1DeployManagerAd } /** - * Get all available networks + * Get all available production networks */ export function getAvailableNetworks(): string[] { return Object.keys(NETWORK_CONFIGS); } - -/** - * Get testnet networks only - */ -export function getTestnetNetworks(): string[] { - return Object.keys(NETWORK_CONFIGS).filter((name) => NETWORK_CONFIGS[name].isTestnet); -} - -/** - * Get mainnet networks only - */ -export function getMainnetNetworks(): string[] { - return Object.keys(NETWORK_CONFIGS).filter((name) => !NETWORK_CONFIGS[name].isTestnet); -} diff --git a/scripts/deployL1.ts b/scripts/deployL1.ts index 48ce012..d6aef36 100644 --- a/scripts/deployL1.ts +++ b/scripts/deployL1.ts @@ -3,28 +3,34 @@ import { ethers, upgrades } from "hardhat"; import { DeploymentManager, waitForConfirmations, logDeploymentStep } from "./utils/deployment"; /** - * L1 Deployment Script for BytecodeRepository System + * L1 Deployment Script for BytecodeRepository System (PRODUCTION ONLY) * - * This script deploys the core L1 smart contracts: + * This script deploys the core L1 smart contracts on Ethereum Mainnet: * - VersionController (upgradeable UUPS proxy) * - L1DeployManager (upgradeable UUPS proxy) * - MarketFactory (non-upgradeable) * - CometFactoryV2 (non-upgradeable) * - * Configuration: - * - Governor: 0x6d903f6003cca6255D85CcA4D3B5E5146dC33925 - * - Guardian: 0x7d903f6003cca6255D85CcA4D3B5E5146dC33926 - * - CCIP Router: 0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D + * Production Configuration: + * - Governor: 0x6d903f6003cca6255D85CcA4D3B5E5146dC33925 (Ethereum Mainnet Timelock) + * - Guardian: 0x7d903f6003cca6255D85CcA4D3B5E5146dC33926 (Guardian for cooldown resets) + * - CCIP Router: 0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D (Ethereum Mainnet CCIP Router) + * + * Usage: + * ```bash + * npx hardhat run scripts/deployL1.ts --network mainnet + * ``` + * + * NOTE: This script is designed for PRODUCTION deployment on Ethereum Mainnet only. */ // Configuration -const GOVERNOR_ADDRESS = "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925"; +const GOVERNOR_ADDRESS = "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925"; // Address of timelock on Ethereum const GUARDIAN_ADDRESS = "0x7d903f6003cca6255D85CcA4D3B5E5146dC33926"; // Guardian address for resetCooldown functionality const CCIP_ROUTER_ADDRESS = "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D"; const COMET_PROXY_ADMIN = "0x1EC63B5883C3481134FD50D5DAebc83Ecd2E8779"; const ASSET_LIST_FACTORY = "0x1234567890123456789012345678901234567891"; // TODO: change to actual address -const TIMELOCK = "0x1234567890123456789012345678901234567891"; // TODO: change to actual address // Initial version for CometFactoryV2 const INITIAL_VERSION = { @@ -43,12 +49,14 @@ async function main() { const deploymentManager = await DeploymentManager.create(); const [deployer] = await ethers.getSigners(); + const initialAdmin = deployer.address; const network = await ethers.provider.getNetwork(); console.log("Deploying with account:", deployer.address); console.log("Account balance:", ethers.formatEther(await ethers.provider.getBalance(deployer.address)), "ETH"); console.log("Network:", network.name, "| Chain ID:", network.chainId.toString()); console.log("Configuration:"); + console.log("Initial Admin: ", initialAdmin); console.log("Governor:", GOVERNOR_ADDRESS); console.log("Guardian:", GUARDIAN_ADDRESS); console.log("CCIP Router:", CCIP_ROUTER_ADDRESS); @@ -64,7 +72,7 @@ async function main() { console.log("Deploying proxy and implementation..."); const versionController = await upgrades.deployProxy( VersionController, - [GOVERNOR_ADDRESS, GUARDIAN_ADDRESS], // initializer arguments + [initialAdmin, GUARDIAN_ADDRESS], // initializer arguments { initializer: "initialize", kind: "uups" @@ -86,14 +94,13 @@ async function main() { "VersionController", versionController, deploymentTx, - [GOVERNOR_ADDRESS, GUARDIAN_ADDRESS], + [initialAdmin, GUARDIAN_ADDRESS], true // isUpgradeable ); const versionControllerImplAddress = await upgrades.erc1967.getImplementationAddress(versionControllerAddress); console.log("VersionController Proxy:", versionControllerAddress); console.log("VersionController Implementation:", versionControllerImplAddress); - console.log(""); // 2. Deploy L1DeployManager (upgradeable) logDeploymentStep(2, 4, "Deploying L1DeployManager (upgradeable)..."); @@ -142,7 +149,7 @@ async function main() { l1DeployManagerAddress, // bytecodeProvider COMET_PROXY_ADMIN, // cometProxyAdmin ASSET_LIST_FACTORY, // assetListFactory - TIMELOCK // Timelock + GOVERNOR_ADDRESS // timelock (using governor as timelock) ]; console.log("Deploying contract..."); diff --git a/scripts/deployL2.ts b/scripts/deployL2.ts index 379a1fd..55ce95d 100644 --- a/scripts/deployL2.ts +++ b/scripts/deployL2.ts @@ -1,7 +1,8 @@ /** - * BytecodeRepository L2 Deployment Script + * BytecodeRepository L2 Deployment Script (PRODUCTION ONLY) * - * Deploys the complete L2 BytecodeRepository system with network-specific configurations. + * Deploys the complete L2 BytecodeRepository system with network-specific configurations + * on production L2 networks. * * Architecture: * 1. L2DeployManager - CCIP receiver and bytecode storage on L2 @@ -13,17 +14,22 @@ * - Supports custom address override via CLI arguments * - Validates all required addresses before deployment * + * Supported Production Networks: + * - Arbitrum One, Optimism, Polygon, Base + * - Linea, Ronin, Unichain, Mantle, Scroll + * * Usage: * ```bash * # Deploy with network-specific config * npx hardhat run scripts/deployL2.ts --network arbitrum + * npx hardhat run scripts/deployL2.ts --network optimism + * npx hardhat run scripts/deployL2.ts --network polygon * * # Deploy with custom addresses * npx hardhat run scripts/deployL2.ts --network arbitrum -- --timelock 0x123... --ccip-router 0x456... - * - * # Deploy to testnet - * npx hardhat run scripts/deployL2.ts --network arbitrumSepolia * ``` + * + * NOTE: This script is designed for PRODUCTION deployment on L2 mainnets only. */ import hre from "hardhat"; @@ -35,6 +41,7 @@ import { getNetworkConfig, validateNetworkConfig, NetworkConfig } from "./config interface L2DeploymentConfig { // Network-specific addresses (from networkConfig.ts) ccipRouter: string; + sourceChainSelector: string; // CCIP chain selector for L1 source chain timelock: string; cometProxyAdmin: string; assetListFactory: string; @@ -123,6 +130,7 @@ async function loadDeploymentConfig(): Promise { // Create deployment config const config: L2DeploymentConfig = { ccipRouter: networkConfig.ccipRouter, + sourceChainSelector: networkConfig.sourceChainSelector, timelock: networkConfig.timelock, cometProxyAdmin: networkConfig.cometProxyAdmin, assetListFactory: networkConfig.assetListFactory, @@ -140,6 +148,7 @@ async function loadDeploymentConfig(): Promise { console.log(" Deployment Configuration:"); console.log(` CCIP Router: ${config.ccipRouter}`); + console.log(` Source Chain Selector: ${config.sourceChainSelector}`); console.log(` Timelock: ${config.timelock}`); console.log(` Comet Proxy Admin: ${config.cometProxyAdmin}`); console.log(` Asset List Factory: ${config.assetListFactory}`); @@ -165,7 +174,12 @@ async function deployL2DeployManager( const L2DeployManager = await ethers.getContractFactory("L2DeployManager"); // Deploy contract (non-upgradeable) - const l2DeployManager = await L2DeployManager.deploy(config.l1DeployManager, config.ccipRouter, config.timelock); + const l2DeployManager = await L2DeployManager.deploy( + config.sourceChainSelector, + config.l1DeployManager, + config.ccipRouter, + config.timelock + ); // Wait for deployment await l2DeployManager.waitForDeployment(); @@ -179,15 +193,17 @@ async function deployL2DeployManager( "L2DeployManager", l2DeployManager, deploymentTx, - [config.l1DeployManager, config.ccipRouter], + [config.sourceChainSelector, config.l1DeployManager, config.ccipRouter, config.timelock], false // Non-upgradeable ); } const address = await l2DeployManager.getAddress(); console.log(` L2DeployManager deployed: ${address}`); + console.log(` Source Chain Selector: ${config.sourceChainSelector}`); console.log(` L1 Deploy Manager: ${config.l1DeployManager}`); console.log(` CCIP Router: ${config.ccipRouter}`); + console.log(` Local Timelock: ${config.timelock}`); return address; } @@ -209,7 +225,8 @@ async function deployMarketFactory( const marketFactory = await MarketFactory.deploy( l2DeployManagerAddress, // IBytecodeProvider config.cometProxyAdmin, - config.assetListFactory + config.assetListFactory, + config.timelock ); // Wait for deployment @@ -310,7 +327,7 @@ async function main() { console.log(` Balance: ${ethers.formatEther(balance)} ETH`); if (balance === 0n) { - throw new Error("Deployer account has no ETH balance"); + throw new Error("Deployer account has no Native Coin balance"); } console.log("\\nSTARTING L2 DEPLOYMENTS"); From a3a3a2d3d6169949309177e9d69326a9a6261aeb Mon Sep 17 00:00:00 2001 From: philippWOOF Date: Thu, 16 Oct 2025 13:17:39 +0300 Subject: [PATCH 02/11] chore(abi): update --- abi/full/contracts/VersionController.sol/VersionController.json | 2 +- abi/json/contracts/VersionController.sol/VersionController.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/abi/full/contracts/VersionController.sol/VersionController.json b/abi/full/contracts/VersionController.sol/VersionController.json index a8392f0..a62b0a8 100644 --- a/abi/full/contracts/VersionController.sol/VersionController.json +++ b/abi/full/contracts/VersionController.sol/VersionController.json @@ -83,7 +83,7 @@ "function getVerifiedBytecode(tuple(bytes32 contractType, tuple(tuple(uint64 major, uint64 minor, uint64 patch) version, string alternative) version) _version) view returns (bytes)", "function grantRole(bytes32 role, address account)", "function hasRole(bytes32 role, address account) view returns (bool)", - "function initialize(address _governor, address _guardian)", + "function initialize(address _initialAdmin, address _guardian)", "function isBytecodeUploaded(bytes32) view returns (bool)", "function isBytecodeVerified(tuple(bytes32 contractType, tuple(tuple(uint64 major, uint64 minor, uint64 patch) version, string alternative) version) _version) view returns (bool)", "function isDeveloper(address _account) view returns (bool)", diff --git a/abi/json/contracts/VersionController.sol/VersionController.json b/abi/json/contracts/VersionController.sol/VersionController.json index cf534e9..a38ab94 100644 --- a/abi/json/contracts/VersionController.sol/VersionController.json +++ b/abi/json/contracts/VersionController.sol/VersionController.json @@ -1538,7 +1538,7 @@ "inputs": [ { "internalType": "address", - "name": "_governor", + "name": "_initialAdmin", "type": "address" }, { From 44c036dd25c9b3ed8c3de3acbaaef88ca2cdcfd3 Mon Sep 17 00:00:00 2001 From: philippWOOF Date: Thu, 16 Oct 2025 13:19:18 +0300 Subject: [PATCH 03/11] chore(contract-docs): update --- docs/VersionController.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/VersionController.md b/docs/VersionController.md index d08c136..9df68f2 100644 --- a/docs/VersionController.md +++ b/docs/VersionController.md @@ -187,7 +187,7 @@ constructor() public ### initialize ```solidity -function initialize(address _governor, address _guardian) external +function initialize(address _initialAdmin, address _guardian) external ``` ### checkDeveloper From 928c95021a13cc5125efccd6cf210fedeeadc758 Mon Sep 17 00:00:00 2001 From: philippWOOF Date: Thu, 16 Oct 2025 13:21:18 +0300 Subject: [PATCH 04/11] chore: set configs after deployment --- scripts/setConfigsL1.ts | 587 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 587 insertions(+) create mode 100644 scripts/setConfigsL1.ts diff --git a/scripts/setConfigsL1.ts b/scripts/setConfigsL1.ts new file mode 100644 index 0000000..cf4fd60 --- /dev/null +++ b/scripts/setConfigsL1.ts @@ -0,0 +1,587 @@ +/** + * L1 Chain Configuration Script + * + * This script performs comprehensive L1 configuration after L2 deployments are complete: + * - Configures L2 chain settings in L1DeployManager + * - Assigns key developers to contract types + * - Grants auditor roles + * - Transfers admin role to permanent governor + * + * IMPORTANT: This script requires the deployer to have DEFAULT_ADMIN_ROLE in VersionController. + * The deployer receives this role during initial deployment (deployL1.ts). + * + * Flow: + * 1. Validate developer and auditor addresses (warn about placeholders) + * 2. Read deployed L2DeployManager addresses from deployment artifacts + * 3. Configure each L2 chain in L1DeployManager using setChainConfig() + * 4. Validate all configurations + * 5. GRANT DEFAULT_ADMIN_ROLE to permanent governor (CRITICAL STEP) + * 6. Validate permanent governor has the role + * 7. Assign key developer to all 12 contract types + * 8. Grant AUDITOR_ROLE to configured auditors + * 9. Display role assignment summary + * 10. Renounce DEFAULT_ADMIN_ROLE from deployer (permanent governor retains role) + * + * Role Management: + * - Deployer starts with DEFAULT_ADMIN_ROLE (granted in deployL1.ts) + * - This script grants DEFAULT_ADMIN_ROLE to permanent governor + * - One key developer is assigned to all contract types and receives KEY_DEVELOPER_ROLE + * - Auditors receive AUDITOR_ROLE for bytecode verification + * - Deployer renounces their DEFAULT_ADMIN_ROLE (unless deployer IS the governor) + * - Final state: Only permanent governor has DEFAULT_ADMIN_ROLE + * + * Contract Types (all assigned to single key developer): + * - CometWithAssetList, CometExtWithAssetList + * - CompoundGovernor + * - VersionController, L1DeployManager, L2DeployManager + * - MarketFactory, CometFactoryV2 + * - Streamer, StreamerFactory + * - CometMultiplier, CometCollateralSwap + * + * BEFORE RUNNING: + * 1. Update KEY_DEVELOPER address (replace placeholder 0x1234567890123456789012345678901234567890) + * 2. Update auditor addresses (AUDITOR_1, AUDITOR_2) + * 3. Ensure L2 contracts are already deployed + * 4. Verify deployer has sufficient gas + * + * Usage: + * ```bash + * # Configure L2 chains on Ethereum mainnet (PRODUCTION ONLY) + * npx hardhat run scripts/setConfigsL1.ts --network mainnet + * ``` + * + * NOTE: This script is designed for PRODUCTION deployment on Ethereum Mainnet only. + * It does not support testnet deployments. + */ + +import hre from "hardhat"; +import { ethers } from "hardhat"; +import fs from "fs"; +import path from "path"; +import { getNetworkConfig, NETWORK_CONFIGS } from "./config/networkConfig"; + +// L1 configuration +const L1_GOVERNOR_ADDRESS = "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925"; // Permanent governor + +// Developer address for all contract type assignments +// TODO: Replace with actual developer address before deployment +const KEY_DEVELOPER = "0x1234567890123456789012345678901234567890"; // Main key developer for all contract types + +// Auditor addresses +// TODO: Replace with actual auditor addresses before deployment +const AUDITOR_1 = "0x7234567890123456789012345678901234567890"; // Primary auditor + +// All contract types to be assigned to the key developer +const CONTRACT_TYPES = [ + // Comet contracts + "CometWithAssetList", + "CometExtWithAssetList", + + // Governance + "CompoundGovernor", + + // Core system + "VersionController", + "L1DeployManager", + "L2DeployManager", + + // Factories + "MarketFactory", + "CometFactoryV2", + + // Streaming + "Streamer", + "StreamerFactory", + + // Utilities + "CometMultiplier", + "CometCollateralSwap" +]; + +// Auditors to grant roles +const AUDITORS = [{ address: AUDITOR_1, name: "Certora Auditor" }]; + +// ChainConfig struct matches IL1DeployManager.sol:41-44 +interface ChainConfig { + l2DeployManager: string; + destinationChainSelector: string; // uint64 as string +} + +interface L2DeploymentInfo { + chainId: number; + networkName: string; + l2DeployManagerAddress: string; + destinationChainSelector: string; +} + +/** + * Read L2DeployManager address from deployment artifacts + */ +function getL2DeploymentInfo(networkName: string): L2DeploymentInfo | null { + try { + const deploymentPath = path.join(__dirname, "..", "deployments", networkName, "L2DeployManager.json"); + + if (!fs.existsSync(deploymentPath)) { + console.log(`⚠️ No deployment found for ${networkName}`); + return null; + } + + const deployment = JSON.parse(fs.readFileSync(deploymentPath, "utf8")); + const networkConfig = NETWORK_CONFIGS[networkName]; + + return { + chainId: networkConfig.chainId, + networkName: networkConfig.name, + l2DeployManagerAddress: deployment.address, + destinationChainSelector: networkConfig.sourceChainSelector // CCIP selector for L2 chain + }; + } catch (error) { + console.error(`Error reading deployment for ${networkName}:`, error); + return null; + } +} + +/** + * Get all L2 networks to configure for Ethereum Mainnet + */ +function getL2NetworksForL1(l1ChainId: bigint): string[] { + // Ethereum Mainnet (1) -> L2 production networks + if (l1ChainId === 1n) { + return ["arbitrum", "optimism", "polygon", "base", "linea", "ronin", "unichain", "mantle", "scroll"]; + } else { + throw new Error( + `Unsupported L1 network with chain ID: ${l1ChainId}. ` + + `This script is designed for production deployment on Ethereum Mainnet only (chain ID 1).` + ); + } +} + +/** + * Validate deployer has DEFAULT_ADMIN_ROLE + */ +async function validateDeployerRole(versionController: any, deployerAddress: string): Promise { + const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + const hasRole = await versionController.hasRole(DEFAULT_ADMIN_ROLE, deployerAddress); + + if (!hasRole) { + throw new Error( + `Deployer ${deployerAddress} does NOT have DEFAULT_ADMIN_ROLE.\n` + + `Governor must grant this role before running this script:\n` + + `versionController.grantRole(DEFAULT_ADMIN_ROLE, "${deployerAddress}")` + ); + } + + console.log("✓ Deployer has DEFAULT_ADMIN_ROLE"); +} + +/** + * Validate governor retains DEFAULT_ADMIN_ROLE after renunciation + */ +async function validateGovernorRole(versionController: any, governorAddress: string): Promise { + const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + const hasRole = await versionController.hasRole(DEFAULT_ADMIN_ROLE, governorAddress); + + if (!hasRole) { + throw new Error(`CRITICAL: Governor ${governorAddress} does NOT have DEFAULT_ADMIN_ROLE!`); + } + + console.log("✓ Governor retains DEFAULT_ADMIN_ROLE:", governorAddress); +} + +/** + * Validate developer address is not a placeholder address + */ +function validateDeveloperAddress(): void { + const placeholderPattern = /^0x[0-9]+$/; + + if (placeholderPattern.test(KEY_DEVELOPER)) { + console.warn("⚠️ WARNING: KEY_DEVELOPER uses a placeholder address:"); + console.warn(` - KEY_DEVELOPER: ${KEY_DEVELOPER}`); + console.warn(" Please update this address before production deployment!"); + console.warn(""); + } +} + +/** + * Validate auditor addresses are not placeholder addresses + */ +function validateAuditorAddresses(): void { + const placeholderPattern = /^0x[0-9]+$/; + const invalidAuditors = AUDITORS.filter((auditor) => placeholderPattern.test(auditor.address)); + + if (invalidAuditors.length > 0) { + console.warn("⚠️ WARNING: The following auditors use placeholder addresses:"); + invalidAuditors.forEach((auditor) => console.warn(` - ${auditor.name}: ${auditor.address}`)); + console.warn(" Please update these addresses before production deployment!"); + console.warn(""); + } +} + +/** + * Assign key developer for all contract types + */ +async function assignKeyDeveloper(versionController: any): Promise { + console.log("Step 7: Assigning key developer for contract types..."); + console.log(""); + + const KEY_DEVELOPER_ROLE = ethers.keccak256(ethers.toUtf8Bytes("KEY_DEVELOPER_ROLE")); + + console.log(` Developer: ${KEY_DEVELOPER}`); + console.log(` Contract Types (${CONTRACT_TYPES.length}):`); + CONTRACT_TYPES.forEach((ct, idx) => { + console.log(` ${idx + 1}. ${ct}`); + }); + console.log(""); + + // Convert contract type strings to bytes32 + const contractTypesBytes32 = CONTRACT_TYPES.map((ct: string) => ethers.encodeBytes32String(ct)); + + try { + // Check if developer already has KEY_DEVELOPER_ROLE + const hasRole = await versionController.hasRole(KEY_DEVELOPER_ROLE, KEY_DEVELOPER); + console.log( + ` Developer has KEY_DEVELOPER_ROLE: ${hasRole ? "Yes (already assigned)" : "No (will be granted)"}` + ); + console.log(""); + + // Assign developer for contract types (this will grant KEY_DEVELOPER_ROLE if needed) + console.log(" Executing assignment transaction..."); + const tx = await versionController.assignDeveloperForContractTypes(contractTypesBytes32, KEY_DEVELOPER); + console.log(` Transaction hash: ${tx.hash}`); + + const receipt = await tx.wait(1); + console.log(` ✓ Confirmed in block ${receipt?.blockNumber}`); + console.log(""); + + // Verify assignments + console.log(" Verifying assignments..."); + let verifiedCount = 0; + for (let i = 0; i < contractTypesBytes32.length; i++) { + const assignedDev = await versionController.contractTypeKeyDeveloper(contractTypesBytes32[i]); + if (assignedDev.toLowerCase() !== KEY_DEVELOPER.toLowerCase()) { + throw new Error( + `Assignment verification failed for ${CONTRACT_TYPES[i]}: expected ${KEY_DEVELOPER}, got ${assignedDev}` + ); + } + verifiedCount++; + } + console.log(` ✓ All ${verifiedCount} contract type(s) assigned and verified`); + + // Verify developer has KEY_DEVELOPER_ROLE + const hasRoleAfter = await versionController.hasRole(KEY_DEVELOPER_ROLE, KEY_DEVELOPER); + if (!hasRoleAfter) { + throw new Error(`Developer ${KEY_DEVELOPER} does not have KEY_DEVELOPER_ROLE after assignment`); + } + console.log(` ✓ Developer has KEY_DEVELOPER_ROLE`); + } catch (error: any) { + // Check if error is due to same key developer already assigned + if (error.message && error.message.includes("SameKeyDeveloper")) { + console.log(` ℹ️ Contract types already assigned to this developer`); + } else { + throw error; + } + } + + console.log(""); + console.log("✓ Key developer assignment completed successfully"); + console.log(""); +} + +/** + * Grant auditor roles + */ +async function grantAuditorRoles(versionController: any): Promise { + console.log("Step 8: Granting auditor roles..."); + console.log(""); + + const AUDITOR_ROLE = ethers.keccak256(ethers.toUtf8Bytes("AUDITOR_ROLE")); + + for (const auditor of AUDITORS) { + console.log(` Granting AUDITOR_ROLE to ${auditor.name}:`); + console.log(` Address: ${auditor.address}`); + + try { + // Check if auditor already has the role + const hasRole = await versionController.hasRole(AUDITOR_ROLE, auditor.address); + + if (!hasRole) { + const tx = await versionController.grantRole(AUDITOR_ROLE, auditor.address); + console.log(` Transaction hash: ${tx.hash}`); + + const receipt = await tx.wait(1); + console.log(` ✓ Confirmed in block ${receipt?.blockNumber}`); + + // Verify role was granted + const hasRoleAfter = await versionController.hasRole(AUDITOR_ROLE, auditor.address); + if (!hasRoleAfter) { + throw new Error(`Failed to grant AUDITOR_ROLE to ${auditor.address}`); + } + console.log(` ✓ AUDITOR_ROLE granted and verified`); + } else { + console.log(` ℹ️ Already has AUDITOR_ROLE`); + } + } catch (error) { + console.error(` ❌ Failed to grant role to ${auditor.name}:`, error); + throw error; + } + + console.log(""); + } + + console.log("✓ All auditor roles granted successfully"); + console.log(""); +} + +/** + * Display role assignment summary + */ +async function displayRolesSummary(versionController: any): Promise { + console.log("Role Assignment Summary:"); + console.log("─".repeat(60)); + + const KEY_DEVELOPER_ROLE = ethers.keccak256(ethers.toUtf8Bytes("KEY_DEVELOPER_ROLE")); + const AUDITOR_ROLE = ethers.keccak256(ethers.toUtf8Bytes("AUDITOR_ROLE")); + + // Display key developer + console.log("\nKey Developer:"); + const hasDevRole = await versionController.hasRole(KEY_DEVELOPER_ROLE, KEY_DEVELOPER); + console.log(` ${KEY_DEVELOPER}:`); + console.log(` Has KEY_DEVELOPER_ROLE: ${hasDevRole ? "✓" : "✗"}`); + console.log(` Assigned Contract Types: ${CONTRACT_TYPES.length}`); + CONTRACT_TYPES.forEach((ct) => { + console.log(` - ${ct}`); + }); + + // Display auditors + console.log("\nAuditors:"); + for (const auditor of AUDITORS) { + const hasRole = await versionController.hasRole(AUDITOR_ROLE, auditor.address); + console.log(` ${auditor.name} (${auditor.address}):`); + console.log(` Has AUDITOR_ROLE: ${hasRole ? "✓" : "✗"}`); + } + + console.log(""); +} + +/** + * Main configuration function + */ +async function main() { + console.log("L1 CHAIN CONFIGURATION SCRIPT"); + console.log("═".repeat(60)); + + // Get network info + const network = await ethers.provider.getNetwork(); + const [deployer] = await ethers.getSigners(); + + console.log(`\nNetwork: ${network.name} (Chain ID: ${network.chainId})`); + console.log(`Deployer: ${deployer.address}`); + console.log(`Permanent Governor: ${L1_GOVERNOR_ADDRESS}`); + console.log(""); + + // Validate addresses + console.log("Validating Configuration..."); + validateDeveloperAddress(); + validateAuditorAddresses(); + console.log(""); + + try { + // Load deployed contracts + const deploymentPath = path.join(__dirname, "..", "deployments", network.name, "deployments.json"); + if (!fs.existsSync(deploymentPath)) { + throw new Error(`No deployments found for network: ${network.name}`); + } + + const deployments = JSON.parse(fs.readFileSync(deploymentPath, "utf8")); + const versionControllerAddress = deployments.VersionController; + const l1DeployManagerAddress = deployments.L1DeployManager; + + if (!versionControllerAddress || !l1DeployManagerAddress) { + throw new Error("VersionController or L1DeployManager not found in deployments"); + } + + console.log("Loaded Contract Addresses:"); + console.log(` VersionController: ${versionControllerAddress}`); + console.log(` L1DeployManager: ${l1DeployManagerAddress}`); + console.log(""); + + // Get contract instances + const versionController = await ethers.getContractAt("VersionController", versionControllerAddress); + const l1DeployManager = await ethers.getContractAt("L1DeployManager", l1DeployManagerAddress); + + // Validate deployer has admin role + console.log("Step 1: Validating deployer permissions..."); + await validateDeployerRole(versionController, deployer.address); + console.log(""); + + // Get L2 networks to configure + const l2Networks = getL2NetworksForL1(network.chainId); + console.log(`Step 2: Loading L2 deployment information for ${l2Networks.length} networks...`); + + const l2Deployments: L2DeploymentInfo[] = []; + for (const networkName of l2Networks) { + const info = getL2DeploymentInfo(networkName); + if (info) { + l2Deployments.push(info); + console.log(` ✓ ${info.networkName} (Chain ID: ${info.chainId})`); + console.log(` L2DeployManager: ${info.l2DeployManagerAddress}`); + console.log(` CCIP Selector: ${info.destinationChainSelector}`); + } + } + + if (l2Deployments.length === 0) { + throw new Error("No L2 deployments found. Deploy L2 contracts first using deployL2.ts"); + } + + console.log(`\n Found ${l2Deployments.length} L2 deployment(s)`); + console.log(""); + + // Configure each L2 chain + console.log("Step 3: Configuring L2 chains in L1DeployManager..."); + + for (const l2Info of l2Deployments) { + console.log(`\n Configuring ${l2Info.networkName} (Chain ID: ${l2Info.chainId})...`); + + const chainConfig: ChainConfig = { + l2DeployManager: l2Info.l2DeployManagerAddress, + destinationChainSelector: l2Info.destinationChainSelector + }; + + // Call setChainConfig + const tx = await l1DeployManager.setChainConfig(l2Info.chainId, chainConfig); + console.log(` Transaction hash: ${tx.hash}`); + + const receipt = await tx.wait(1); + console.log(` ✓ Confirmed in block ${receipt?.blockNumber}`); + + // Verify configuration + const storedConfig = await l1DeployManager.chainConfigs(l2Info.chainId); + if ( + storedConfig.l2DeployManager.toLowerCase() !== chainConfig.l2DeployManager.toLowerCase() || + storedConfig.destinationChainSelector.toString() !== chainConfig.destinationChainSelector + ) { + throw new Error(`Configuration verification failed for ${l2Info.networkName}`); + } + console.log(` ✓ Configuration verified on-chain`); + } + + console.log("\n✓ All L2 chains configured successfully"); + console.log(""); + + // Grant DEFAULT_ADMIN_ROLE to permanent governor + console.log("Step 4: Granting DEFAULT_ADMIN_ROLE to permanent governor..."); + const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + + // Check if governor already has the role + const governorHasRole = await versionController.hasRole(DEFAULT_ADMIN_ROLE, L1_GOVERNOR_ADDRESS); + + if (!governorHasRole) { + console.log(` Granting role to: ${L1_GOVERNOR_ADDRESS}`); + const grantTx = await versionController.grantRole(DEFAULT_ADMIN_ROLE, L1_GOVERNOR_ADDRESS); + console.log(` Transaction hash: ${grantTx.hash}`); + + const grantReceipt = await grantTx.wait(1); + console.log(` ✓ Confirmed in block ${grantReceipt?.blockNumber}`); + + // Verify governor now has role + const verifyRole = await versionController.hasRole(DEFAULT_ADMIN_ROLE, L1_GOVERNOR_ADDRESS); + if (!verifyRole) { + throw new Error("Failed to grant DEFAULT_ADMIN_ROLE to governor"); + } + console.log(" ✓ Governor granted DEFAULT_ADMIN_ROLE"); + } else { + console.log(" ✓ Governor already has DEFAULT_ADMIN_ROLE"); + } + console.log(""); + + // Validate governor has role before deployer renounces + console.log("Step 5: Validating permanent governor role..."); + await validateGovernorRole(versionController, L1_GOVERNOR_ADDRESS); + console.log(""); + + // Assign key developer for contract types + console.log("Step 6: Setting up developer and auditor roles..."); + console.log("═".repeat(60)); + console.log(""); + await assignKeyDeveloper(versionController); + await grantAuditorRoles(versionController); + + // Display role assignments summary + await displayRolesSummary(versionController); + + // Renounce deployer's DEFAULT_ADMIN_ROLE + console.log("Step 9: Renouncing deployer's DEFAULT_ADMIN_ROLE..."); + console.log("⚠️ WARNING: This action is IRREVERSIBLE"); + + console.log(` Deployer: ${deployer.address}`); + console.log(` Renouncing role: DEFAULT_ADMIN_ROLE`); + + const renounceTx = await versionController.renounceRole(DEFAULT_ADMIN_ROLE, deployer.address); + console.log(` Transaction hash: ${renounceTx.hash}`); + + const renounceReceipt = await renounceTx.wait(1); + console.log(` ✓ Confirmed in block ${renounceReceipt?.blockNumber}`); + + // Verify deployer no longer has role + const stillHasRole = await versionController.hasRole(DEFAULT_ADMIN_ROLE, deployer.address); + if (stillHasRole) { + throw new Error("Role renunciation failed - deployer still has DEFAULT_ADMIN_ROLE"); + } + console.log(" ✓ Deployer no longer has DEFAULT_ADMIN_ROLE"); + + // Final validation that governor retains role + await validateGovernorRole(versionController, L1_GOVERNOR_ADDRESS); + + console.log(""); + console.log("═".repeat(60)); + console.log("🎉 L1 CHAIN CONFIGURATION COMPLETED SUCCESSFULLY!"); + console.log("═".repeat(60)); + console.log(""); + console.log("Summary:"); + console.log(` - Configured ${l2Deployments.length} L2 chain(s)`); + console.log(` - Permanent Governor has DEFAULT_ADMIN_ROLE: ${L1_GOVERNOR_ADDRESS}`); + console.log(` - Assigned key developer to ${CONTRACT_TYPES.length} contract type(s)`); + console.log(` - Granted AUDITOR_ROLE to ${AUDITORS.length} auditor(s)`); + + if (deployer.address.toLowerCase() !== L1_GOVERNOR_ADDRESS.toLowerCase()) { + console.log(` - Deployer role renounced: ${deployer.address}`); + } else { + console.log(` - Deployer IS permanent governor (role retained)`); + } + console.log(""); + console.log("Role Management Complete:"); + console.log(" ✓ Permanent governor has DEFAULT_ADMIN_ROLE"); + console.log(" ✓ Deployer admin role properly transferred/renounced"); + console.log(" ✓ Key developer assigned to all contract types"); + console.log(" ✓ Auditor roles granted"); + console.log(""); + console.log("Next Steps:"); + console.log(" 1. Verify L2 chain configurations:"); + console.log(` l1DeployManager.chainConfigs()`); + console.log(" 2. Verify governor role:"); + console.log(` versionController.hasRole(DEFAULT_ADMIN_ROLE, "${L1_GOVERNOR_ADDRESS}")`); + console.log(" 3. Verify developer assignments:"); + console.log(` versionController.contractTypeKeyDeveloper()`); + console.log(" 4. Verify auditor roles:"); + console.log(` versionController.hasRole(AUDITOR_ROLE, )`); + console.log(" 5. Developers can now upload bytecode for their assigned contract types"); + console.log(" 6. Auditors can verify uploaded bytecode with EIP-712 signatures"); + console.log(" 7. Test cross-chain bytecode transmission"); + console.log(""); + } catch (error) { + console.error("\n❌ Configuration failed:", error); + process.exit(1); + } +} + +// Handle unhandled promise rejections +process.on("unhandledRejection", (reason, promise) => { + console.error("Unhandled Rejection at:", promise, "reason:", reason); + process.exit(1); +}); + +if (require.main === module) { + main(); +} + +export default main; From feb453172b3622a5ad94447efcf962e7a7b7500a Mon Sep 17 00:00:00 2001 From: philippWOOF Date: Thu, 16 Oct 2025 14:00:55 +0300 Subject: [PATCH 05/11] chore: update addresses in config --- scripts/config/networkConfig.ts | 97 ++++++++++++++++++--------------- scripts/deployL1.ts | 2 +- scripts/setConfigsL1.ts | 2 +- 3 files changed, 55 insertions(+), 46 deletions(-) diff --git a/scripts/config/networkConfig.ts b/scripts/config/networkConfig.ts index 7b516d2..3344a91 100644 --- a/scripts/config/networkConfig.ts +++ b/scripts/config/networkConfig.ts @@ -4,6 +4,8 @@ * This file contains all network-specific addresses needed for L2 contract deployments. * Each network configuration includes: * - CCIP Router address for cross-chain messaging + * - Source Chain Selector: Ethereum Mainnet CCIP selector (5009297550715157269) - used in L2DeployManager + * - Destination Chain Selector: This L2's CCIP selector - used in L1DeployManager setChainConfig * - Timelock address for governance (CometFactoryV2) * - CometProxyAdmin address for proxy management (MarketFactory) * - AssetListFactory address for asset list functionality (MarketFactory) @@ -14,7 +16,8 @@ export interface NetworkConfig { name: string; chainId: number; ccipRouter: string; - sourceChainSelector: string; // CCIP chain selector for this L2 chain + sourceChainSelector: string; // Ethereum Mainnet CCIP selector (5009297550715157269) - used in L2DeployManager + destinationChainSelector: string; // This L2's CCIP selector - used in L1DeployManager setChainConfig timelock: string; cometProxyAdmin: string; assetListFactory: string; @@ -22,50 +25,51 @@ export interface NetworkConfig { } export const NETWORK_CONFIGS: Record = { - // Ethereum L2s - Mainnet + // Ethereum L2s - Production Mainnet arbitrum: { name: "arbitrum", chainId: 42161, - ccipRouter: "0x141fa059441e0ca23ce184b6a78ba4b7c0a30fb0", - sourceChainSelector: "4949039107694359620", // Arbitrum One CCIP chain selector - timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Arbitrum Timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + ccipRouter: "0x141fa059441E0ca23ce184B6A78bafD2A517DdE8", + sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector + destinationChainSelector: "4949039107694359620", // Arbitrum One CCIP selector + timelock: "0x3fB4d38ea7EC20D91917c09591490Eeda38Cf88A", // Arbitrum Timelock + cometProxyAdmin: "0xD10b40fF1D92e2267D099Da3509253D9Da4D715e", assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual - l1DeployManager: "0x1234567890123456789012345678901234567890", // Will be set from L1 deployment - isTestnet: false + l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, optimism: { name: "optimism", chainId: 10, - ccipRouter: "0x3c3d92629a02a8d95d5cb9650fe49c3544f69b43", - sourceChainSelector: "3734403246176062136", // OP Mainnet CCIP chain selector - timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Optimism Timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + ccipRouter: "0x3206695CaE29952f4b0c22a169725a865bc8Ce0f", + sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector + destinationChainSelector: "3734403246176062136", // OP Mainnet CCIP selector + timelock: "0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07", // Optimism Timelock + cometProxyAdmin: "0x24D86Da09C4Dd64e50dB7501b0f695d030f397aF", assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual - l1DeployManager: "0x1234567890123456789012345678901234567890", // Will be set from L1 deployment - isTestnet: false + l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, polygon: { name: "polygon", chainId: 137, - ccipRouter: "0x849c5ed5a80f5b408dd4caa5fe8c2b852aff67a9", - sourceChainSelector: "4051577828743386545", // Polygon CCIP chain selector - timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Polygon Timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + ccipRouter: "0x849c5ED5a80F5B408Dd4969b78c2C8fdf0565Bfe", + sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector + destinationChainSelector: "4051577828743386545", // Polygon CCIP selector + timelock: "0xCC3E7c85Bb0EE4f09380e041fee95a0caeDD4a02", // Polygon Timelock + cometProxyAdmin: "0xd712ACe4ca490D4F3E92992Ecf3DE12251b975F9", assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual - l1DeployManager: "0x1234567890123456789012345678901234567890", // Will be set from L1 deployment - isTestnet: false + l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, base: { name: "base", chainId: 8453, - ccipRouter: "0x881e3a65b4d4a04dd529061dd0071cf975f58bcd", - sourceChainSelector: "15971525489660198786", // Base CCIP chain selector - timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Base Timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + ccipRouter: "0x881e3A65B4d4a04dD529061dd0071cf975F58bCD", + sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector + destinationChainSelector: "15971525489660198786", // Base CCIP selector + timelock: "0xCC3E7c85Bb0EE4f09380e041fee95a0caeDD4a02", // Base Timelock + cometProxyAdmin: "0xbdE8F31D2DdDA895264e27DD990faB3DC87b372d", assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -73,10 +77,11 @@ export const NETWORK_CONFIGS: Record = { linea: { name: "linea", chainId: 59144, - ccipRouter: "0x549F800f7C8a012C5501C011a85d20baBC51d845", // TODO: Verify actual router address - sourceChainSelector: "4627098889531055414", // Linea CCIP chain selector - timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Linea Timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + ccipRouter: "0x549FEB73F2348F6cD99b9fc8c69252034897f06C", + sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector + destinationChainSelector: "4627098889531055414", // Linea CCIP selector + timelock: "0x1234567890123456789012345678901234567890", // Placeholder Linea Timelock + cometProxyAdmin: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -84,10 +89,11 @@ export const NETWORK_CONFIGS: Record = { ronin: { name: "ronin", chainId: 2020, - ccipRouter: "0x0000000000000000000000000000000000000000", // TODO: Add actual router address - sourceChainSelector: "6916147374840168594", // Ronin CCIP chain selector - timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Ronin Timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + ccipRouter: "0x46527571D5D1B68eE7Eb60B18A32e6C60DcEAf99", + sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector + destinationChainSelector: "6916147374840168594", // Ronin CCIP selector + timelock: "0x1234567890123456789012345678901234567890", // Placeholder Ronin Timelock + cometProxyAdmin: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -95,10 +101,11 @@ export const NETWORK_CONFIGS: Record = { unichain: { name: "unichain", chainId: 130, - ccipRouter: "0x0000000000000000000000000000000000000000", // TODO: Add actual router address when available - sourceChainSelector: "0", // TODO: Add actual CCIP chain selector when available - timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Unichain Timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + ccipRouter: "0x68891f5F96695ECd7dEdBE2289D1b73426ae7864", + sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector + destinationChainSelector: "1923510103922296319", // TUnichain CCIP selector + timelock: "0x1234567890123456789012345678901234567890", // Placeholder Unichain Timelock + cometProxyAdmin: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -106,10 +113,11 @@ export const NETWORK_CONFIGS: Record = { mantle: { name: "mantle", chainId: 5000, - ccipRouter: "0x0000000000000000000000000000000000000000", // TODO: Verify actual router address - sourceChainSelector: "1556008542357238666", // Mantle CCIP chain selector - timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Mantle Timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + ccipRouter: "0x670052635a9850bb45882Cb2eCcF66bCff0F41B7", + sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector + destinationChainSelector: "1556008542357238666", // Mantle CCIP selector + timelock: "0x16C7B5C1b10489F4B111af11de2Bd607c9728107", // Mantle Timelock + cometProxyAdmin: "0xe268B436E75648aa0639e2088fa803feA517a0c7", assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -117,10 +125,11 @@ export const NETWORK_CONFIGS: Record = { scroll: { name: "scroll", chainId: 534352, - ccipRouter: "0x0000000000000000000000000000000000000000", // TODO: Verify actual router address - sourceChainSelector: "13204309965629103672", // Scroll CCIP chain selector - timelock: "0x4Abae72C27A82C1462fa58Ab9c34fe690e10fe72", // Scroll Timelock - cometProxyAdmin: "0x8c41E9f05b8BBcC844cF5E79c8B4A02e73c3D9C7", // Placeholder - replace with actual + ccipRouter: "0x9a55E8Cab6564eb7bbd7124238932963B8Af71DC", + sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector + destinationChainSelector: "13204309965629103672", // Scroll CCIP selector + timelock: "0xF6013e80E9e6AC211Cc031ad1CE98B3Aa20b73E4", + cometProxyAdmin: "0x87A27b91f4130a25E9634d23A5B8E05e342bac50", assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment } diff --git a/scripts/deployL1.ts b/scripts/deployL1.ts index d6aef36..3a347a7 100644 --- a/scripts/deployL1.ts +++ b/scripts/deployL1.ts @@ -26,7 +26,7 @@ import { DeploymentManager, waitForConfirmations, logDeploymentStep } from "./ut // Configuration const GOVERNOR_ADDRESS = "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925"; // Address of timelock on Ethereum -const GUARDIAN_ADDRESS = "0x7d903f6003cca6255D85CcA4D3B5E5146dC33926"; // Guardian address for resetCooldown functionality +const GUARDIAN_ADDRESS = "0xbbf3f1421D886E9b2c5D716B5192aC998af2012c"; // Guardian address for resetCooldown functionality const CCIP_ROUTER_ADDRESS = "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D"; const COMET_PROXY_ADMIN = "0x1EC63B5883C3481134FD50D5DAebc83Ecd2E8779"; diff --git a/scripts/setConfigsL1.ts b/scripts/setConfigsL1.ts index cf4fd60..6b450c4 100644 --- a/scripts/setConfigsL1.ts +++ b/scripts/setConfigsL1.ts @@ -133,7 +133,7 @@ function getL2DeploymentInfo(networkName: string): L2DeploymentInfo | null { chainId: networkConfig.chainId, networkName: networkConfig.name, l2DeployManagerAddress: deployment.address, - destinationChainSelector: networkConfig.sourceChainSelector // CCIP selector for L2 chain + destinationChainSelector: networkConfig.destinationChainSelector // CCIP selector for L2 chain }; } catch (error) { console.error(`Error reading deployment for ${networkName}:`, error); From 9587138d2c47347c076dabe5950233775a4f3da3 Mon Sep 17 00:00:00 2001 From: philippWOOF Date: Thu, 16 Oct 2025 14:49:21 +0300 Subject: [PATCH 06/11] chore: extend contract types list --- scripts/setConfigsL1.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/setConfigsL1.ts b/scripts/setConfigsL1.ts index 6b450c4..92e4f19 100644 --- a/scripts/setConfigsL1.ts +++ b/scripts/setConfigsL1.ts @@ -95,7 +95,14 @@ const CONTRACT_TYPES = [ // Utilities "CometMultiplier", - "CometCollateralSwap" + "CometCollateralSwap", + + // CAPO + "ChainlinkCorrelatedAssetsPriceOracle", + "ERC4626CorrelatedAssetsPriceOracle", + "RateBasedCorrelatedAssetsPriceOracle", + "RsETHCorrelatedAssetsPriceOracle", + "WstETHCorrelatedAssetsPriceOracle" ]; // Auditors to grant roles From d111727f060c08c7f7e9af6c720287724ea39545 Mon Sep 17 00:00:00 2001 From: philippWOOF Date: Thu, 16 Oct 2025 15:30:19 +0300 Subject: [PATCH 07/11] chore: add missing addresses in configs --- scripts/config/networkConfig.ts | 26 +++++++++++++------------- scripts/deployL1.ts | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/scripts/config/networkConfig.ts b/scripts/config/networkConfig.ts index 3344a91..a56f8df 100644 --- a/scripts/config/networkConfig.ts +++ b/scripts/config/networkConfig.ts @@ -34,7 +34,7 @@ export const NETWORK_CONFIGS: Record = { destinationChainSelector: "4949039107694359620", // Arbitrum One CCIP selector timelock: "0x3fB4d38ea7EC20D91917c09591490Eeda38Cf88A", // Arbitrum Timelock cometProxyAdmin: "0xD10b40fF1D92e2267D099Da3509253D9Da4D715e", - assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + assetListFactory: "0x17867848406f185CEc6ba91142b15086F7399D85", l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -46,7 +46,7 @@ export const NETWORK_CONFIGS: Record = { destinationChainSelector: "3734403246176062136", // OP Mainnet CCIP selector timelock: "0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07", // Optimism Timelock cometProxyAdmin: "0x24D86Da09C4Dd64e50dB7501b0f695d030f397aF", - assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + assetListFactory: "0x2f7439252Da796Ab9A93f7E478E70DED43Db5B89", l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -70,7 +70,7 @@ export const NETWORK_CONFIGS: Record = { destinationChainSelector: "15971525489660198786", // Base CCIP selector timelock: "0xCC3E7c85Bb0EE4f09380e041fee95a0caeDD4a02", // Base Timelock cometProxyAdmin: "0xbdE8F31D2DdDA895264e27DD990faB3DC87b372d", - assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + assetListFactory: "0x995E394b8B2437aC8Ce61Ee0bC610D617962B214", l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -80,9 +80,9 @@ export const NETWORK_CONFIGS: Record = { ccipRouter: "0x549FEB73F2348F6cD99b9fc8c69252034897f06C", sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector destinationChainSelector: "4627098889531055414", // Linea CCIP selector - timelock: "0x1234567890123456789012345678901234567890", // Placeholder Linea Timelock - cometProxyAdmin: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual - assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + timelock: "0x4A900f81dEdA753bbBab12453b3775D5f26df6F3", + cometProxyAdmin: "0x4b5DeE60531a72C1264319Ec6A22678a4D0C8118", + assetListFactory: "0x2F4eAF29dfeeF4654bD091F7112926E108eF4Ed0", l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -92,9 +92,9 @@ export const NETWORK_CONFIGS: Record = { ccipRouter: "0x46527571D5D1B68eE7Eb60B18A32e6C60DcEAf99", sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector destinationChainSelector: "6916147374840168594", // Ronin CCIP selector - timelock: "0x1234567890123456789012345678901234567890", // Placeholder Ronin Timelock - cometProxyAdmin: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual - assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + timelock: "0xBbb0Ebd903fafbb8fFF58B922fD0CD85E251ac2c", + cometProxyAdmin: "0xfa64A82a3d13D4c05d5133E53b2EbB8A0FA9c3F6", + assetListFactory: "0x84fc63de5d127e9c074c1da6591ee8fa70a60de1", l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -104,9 +104,9 @@ export const NETWORK_CONFIGS: Record = { ccipRouter: "0x68891f5F96695ECd7dEdBE2289D1b73426ae7864", sourceChainSelector: "5009297550715157269", // Ethereum Mainnet CCIP selector destinationChainSelector: "1923510103922296319", // TUnichain CCIP selector - timelock: "0x1234567890123456789012345678901234567890", // Placeholder Unichain Timelock - cometProxyAdmin: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual - assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + timelock: "0x2F4eAF29dfeeF4654bD091F7112926E108eF4Ed0", + cometProxyAdmin: "0xaeB318360f27748Acb200CE616E389A6C9409a07", + assetListFactory: "0x4cfCE7795bF75dC3795369A953d9A9b8C2679AE4", l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -130,7 +130,7 @@ export const NETWORK_CONFIGS: Record = { destinationChainSelector: "13204309965629103672", // Scroll CCIP selector timelock: "0xF6013e80E9e6AC211Cc031ad1CE98B3Aa20b73E4", cometProxyAdmin: "0x87A27b91f4130a25E9634d23A5B8E05e342bac50", - assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + assetListFactory: "0x5404872d8f2e24b230EC9B9eC64E3855F637FB93", l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment } }; diff --git a/scripts/deployL1.ts b/scripts/deployL1.ts index 3a347a7..8b90247 100644 --- a/scripts/deployL1.ts +++ b/scripts/deployL1.ts @@ -30,7 +30,7 @@ const GUARDIAN_ADDRESS = "0xbbf3f1421D886E9b2c5D716B5192aC998af2012c"; // Guardi const CCIP_ROUTER_ADDRESS = "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D"; const COMET_PROXY_ADMIN = "0x1EC63B5883C3481134FD50D5DAebc83Ecd2E8779"; -const ASSET_LIST_FACTORY = "0x1234567890123456789012345678901234567891"; // TODO: change to actual address +const ASSET_LIST_FACTORY = "0x3fF744cF6078714bB9d3c4fE5Ab37fA6d05dEC4E"; // Initial version for CometFactoryV2 const INITIAL_VERSION = { From fc416537e61616acb6e9c9e4fe01af5b3049b13f Mon Sep 17 00:00:00 2001 From: philippWOOF Date: Fri, 17 Oct 2025 15:19:43 +0300 Subject: [PATCH 08/11] chore: add asset list factory addresses in config --- scripts/config/networkConfig.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/config/networkConfig.ts b/scripts/config/networkConfig.ts index a56f8df..3e01448 100644 --- a/scripts/config/networkConfig.ts +++ b/scripts/config/networkConfig.ts @@ -58,7 +58,7 @@ export const NETWORK_CONFIGS: Record = { destinationChainSelector: "4051577828743386545", // Polygon CCIP selector timelock: "0xCC3E7c85Bb0EE4f09380e041fee95a0caeDD4a02", // Polygon Timelock cometProxyAdmin: "0xd712ACe4ca490D4F3E92992Ecf3DE12251b975F9", - assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + assetListFactory: "0xF372E84282FD0F5c631076aD8b9Da6B901E53c78", l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, @@ -118,7 +118,7 @@ export const NETWORK_CONFIGS: Record = { destinationChainSelector: "1556008542357238666", // Mantle CCIP selector timelock: "0x16C7B5C1b10489F4B111af11de2Bd607c9728107", // Mantle Timelock cometProxyAdmin: "0xe268B436E75648aa0639e2088fa803feA517a0c7", - assetListFactory: "0x1234567890123456789012345678901234567890", // Placeholder - replace with actual + assetListFactory: "0x0dAf7A2772C84A82D1D46a4b628151e6D7F5b202", l1DeployManager: "0x1234567890123456789012345678901234567890" // Will be set from L1 deployment }, From 40cbd55e013b1a4d2bfa49dd12625d0b4e2999c1 Mon Sep 17 00:00:00 2001 From: philippWOOF Date: Mon, 23 Mar 2026 11:48:25 +0000 Subject: [PATCH 09/11] chore: script for uploading bytecode via cli --- README.md | 37 ++++ scripts/cli/uploadBytecode.ts | 315 ++++++++++++++++++++++++++++++++ scripts/utils/uploadBytecode.ts | 306 +++++++++++++++++++++++++++++++ 3 files changed, 658 insertions(+) create mode 100644 scripts/cli/uploadBytecode.ts create mode 100644 scripts/utils/uploadBytecode.ts diff --git a/README.md b/README.md index e290e2d..a4be5be 100644 --- a/README.md +++ b/README.md @@ -321,6 +321,43 @@ versionController.addSubDeveloper(subDeveloperAddress); // Same process as key developer, but limited to their key dev's contract types ``` +**Upload via CLI Script** + +The `uploadBytecode.ts` script provides a convenient CLI for uploading bytecode. +It validates developer access before sending a transaction and supports loading bytecode from Hardhat/Foundry artifacts, custom JSON files, or raw hex files. + +```bash +# Initial release (creates version 1.0.0) from a Hardhat compilation artifact +npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + --contract-type Comet \ + --release-type initial \ + --source-url "https://github.com/compound-finance/comet/releases/v1.0.0" \ + --bytecode-file artifacts/contracts/Comet.sol/Comet.json + +# Patch release (creates next patch under 1.0.x) +npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + --contract-type Comet \ + --release-type patch --major 1 --minor 0 \ + --source-url "https://github.com/compound-finance/comet/releases/v1.0.1" \ + --bytecode-file artifacts/contracts/Comet.sol/Comet.json + +# Alternative version (creates 1.0.0-gas-optimized) +npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + --contract-type Comet \ + --release-type alternative --major 1 --minor 0 --patch 0 --alternative gas-optimized \ + --source-url "https://github.com/compound-finance/comet/releases/v1.0.0-gas-optimized" \ + --bytecode-file artifacts/contracts/CometGasOptimized.sol/CometGasOptimized.json + +# Load bytecode from a custom JSON file with a specific key +npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + --contract-type Comet \ + --release-type initial \ + --source-url "https://github.com/..." \ + --bytecode-file bytecodes/contracts.json --json-key CometInitCode +``` + +Run `npx hardhat run scripts/cli/uploadBytecode.ts -- --help` for the full list of flags. + ### Phase 3: Audit & Verification 🔍 **Step 1: Auditor Review Process** diff --git a/scripts/cli/uploadBytecode.ts b/scripts/cli/uploadBytecode.ts new file mode 100644 index 0000000..51f309a --- /dev/null +++ b/scripts/cli/uploadBytecode.ts @@ -0,0 +1,315 @@ +/** + * Bytecode Upload Script + * + * Uploads bytecode to the VersionController contract with support for all release types. + * + * Bytecode File Formats: + * The --bytecode-file flag accepts: + * - Hardhat artifact: artifacts/contracts/Foo.sol/Foo.json (auto-detects `bytecode` field) + * - Foundry artifact: out/Foo.sol/Foo.json (auto-detects `bytecode.object` field) + * - Custom JSON: use --json-key to specify which field (e.g., --json-key CometInitCode) + * - Raw hex file: .hex or .bin files containing the bytecode as a hex string + * + * Usage: + * # Initial release (creates version 1.0.0) + * npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + * --contract-type Comet \ + * --release-type initial \ + * --source-url "https://github.com/compound-finance/comet/blob/main/contracts/Comet.sol" \ + * --bytecode-file artifacts/contracts/Comet.sol/Comet.json + * + * # Major version release + * npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + * --contract-type Comet --release-type major \ + * --source-url "..." --bytecode-file artifacts/contracts/CometV2.sol/CometV2.json + * + * # Minor version release (under major version 1) + * npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + * --contract-type Comet --release-type minor --major 1 \ + * --source-url "..." --bytecode-file path/to/bytecode.json + * + * # Patch version release (under version 1.2.x) + * npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + * --contract-type Comet --release-type patch --major 1 --minor 2 \ + * --source-url "..." --bytecode-file path/to/bytecode.json + * + * # Alternative version (creates 1.0.0-optimized) + * npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + * --contract-type Comet --release-type alternative \ + * --major 1 --minor 0 --patch 0 --alternative optimized \ + * --source-url "..." --bytecode-file path/to/bytecode.json + * + * # Using custom JSON with specific key + * npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + * --contract-type Comet --release-type initial \ + * --source-url "..." \ + * --bytecode-file bytecodes/contracts.json --json-key CometInitCode + * + * # With explicit VersionController address + * npx hardhat run scripts/cli/uploadBytecode.ts --network ethereum -- \ + * --version-controller 0x1234...abcd \ + * --contract-type Comet --release-type initial \ + * --source-url "..." --bytecode-file path/to/bytecode.json + */ + +/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, + @typescript-eslint/no-non-null-assertion, @typescript-eslint/restrict-template-expressions, + @typescript-eslint/use-unknown-in-catch-callback-variable */ + +import { ethers } from "hardhat"; +import fs from "fs"; +import path from "path"; +import { + uploadBytecode, + loadBytecodeFromFile, + formatTargetVersion, + validateDeveloperAccess, + VALID_RELEASE_TYPES, + ReleaseType, + UploadBytecodeParams +} from "../utils/uploadBytecode"; + +const HELP_TEXT = ` +Bytecode Upload Script — uploads bytecode to VersionController + +Required flags: + --contract-type Contract type name (e.g., "Comet", "CometExt") + --release-type One of: ${VALID_RELEASE_TYPES.join(", ")} + --source-url Source code URL + --bytecode-file Path to bytecode file (see formats below) + +Version flags (depend on release type): + --major Major version (required for: minor, patch, alternative) + --minor Minor version (required for: patch, alternative) + --patch Patch version (required for: alternative) + --alternative