diff --git a/.gitignore b/.gitignore index 068ec0ec..93dc207c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ broadcast logs # Dotenv file -.env +.* # npm node_modules diff --git a/Makefile b/Makefile index aa14ebfe..04752c59 100644 --- a/Makefile +++ b/Makefile @@ -138,6 +138,16 @@ simulate: forge build @forge script $(DEPLOY_SCRIPT) --fork-url $(if $(filter sonic,$(NETWORK)),$(SONIC_URL),$(MAINNET_URL)) -vvvv +# ╔══════════════════════════════════════════════════════════════════════════════╗ +# ║ GOVERNANCE ║ +# ╚══════════════════════════════════════════════════════════════════════════════╝ + +# Check on-chain governance state and update deployment JSON +# Usage: make update-governance (mainnet) or make update-governance NETWORK=sonic +update-governance: + forge build + @forge script script/deploy/UpdateGovernance.s.sol --fork-url $(if $(filter sonic,$(NETWORK)),$(SONIC_URL),$(MAINNET_URL)) -vvvvv + # ╔══════════════════════════════════════════════════════════════════════════════╗ # ║ VERIFY ║ # ╚══════════════════════════════════════════════════════════════════════════════╝ @@ -178,4 +188,4 @@ frame: .PHONY: test test-base test-unit test-fork test-smoke test-invariants \ coverage coverage-html gas snapshot \ deploy-mainnet deploy-local deploy-testnet deploy-holesky deploy-sonic simulate \ - match clean clean-crytic clean-all install frame + update-governance match clean clean-crytic clean-all install frame diff --git a/build/deployments-1.json b/build/deployments-1.json index 2c2d4319..6fd178f8 100644 --- a/build/deployments-1.json +++ b/build/deployments-1.json @@ -76,12 +76,20 @@ "implementation": "0x90c7ABC962f96de171ee395A242D2Ff794D0a04c", "name": "MORPHO_MARKET_MEVCAPITAL_IMP" }, + { + "implementation": "0x0ad39D67404aE36Fe476eFDDE1306a5414383544", + "name": "MORPHO_MARKET_ORIGIN" + }, + { + "implementation": "0x2ea9D1827973813D77aA8f35BD23cb1F1311A648", + "name": "MORPHO_MARKET_ORIGIN_IMPL" + }, { "implementation": "0x6bac785889A4127dB0e0CeFEE88E0a9F1Aaf3cC7", "name": "OETH_ARM" }, { - "implementation": "0x187FfF686a5f42ACaaF56469FcCF8e6Feca18248", + "implementation": "0x9a2be51e45eec98f75b3e6e1b334246c94663641", "name": "OETH_ARM_IMPL" }, { @@ -100,63 +108,84 @@ "executions": [ { "name": "001_CoreMainnet", - "timestamp": 1723685111 + "timestampDep": 1723685111, + "timestampGov": 1723685111 }, { "name": "002_UpgradeMainnet", - "timestamp": 1726812322 + "timestampDep": 1726812322, + "timestampGov": 1726812322 }, { "name": "003_UpgradeLidoARMScript", - "timestamp": 1729073099 + "timestampDep": 1729073099, + "timestampGov": 1729073099 }, { "name": "004_UpdateCrossPriceScript", - "timestamp": 1739872139 + "timestampDep": 1739872139, + "timestampGov": 1740476939 }, { "name": "005_RegisterLidoWithdrawalsScript", - "timestamp": 1743500783 + "timestampDep": 1743500783, + "timestampGov": 1744105583 }, { "name": "006_ChangeFeeCollector", - "timestamp": 1751894483 + "timestampDep": 1751894483, + "timestampGov": 1752499283 }, { "name": "007_UpgradeLidoARMMorphoScript", - "timestamp": 1754407511 + "timestampDep": 1754407511, + "timestampGov": 1755012311 }, { "name": "008_DeployPendleAdaptor", - "timestamp": 1755770279 + "timestampDep": 1755770279, + "timestampGov": 1755770279 }, { "name": "009_UpgradeLidoARMSetBufferScript", - "timestamp": 1755692363 + "timestampDep": 1755692363, + "timestampGov": 1756297163 }, { "name": "010_UpgradeLidoARMAssetScript", - "timestamp": 1764755147 + "timestampDep": 1764755147, + "timestampGov": 1765359947 }, { "name": "011_DeployEtherFiARMScript", - "timestamp": 1761812927 + "timestampDep": 1761812927, + "timestampGov": 1761812927 }, { "name": "012_UpgradeEtherFiARMScript", - "timestamp": 1763557643 + "timestampDep": 1763557643, + "timestampGov": 1763557643 + }, + { + "name": "013_UpgradeOETHARMScript", + "timestampDep": 1765353443, + "timestampGov": 1765958243 + }, { "name": "014_DeployEthenaARMScript", - "timestamp": 1764664655 + "timestampDep": 1764664655, + "timestampGov": 1764664655 }, { "name": "015_UpgradeEthenaARMScript", - "timestamp": 1766319523 + "timestampDep": 1766319523, + "timestampGov": 1766319523 }, { "name": "016_UpgradeLidoARMCrossPriceScript", - "timestamp": 1768078823 + "timestampDep": 1768078823, + "timestampGov": 1768683623 } ] } \ No newline at end of file diff --git a/build/deployments-146.json b/build/deployments-146.json index 505c1fe4..b1328219 100644 --- a/build/deployments-146.json +++ b/build/deployments-146.json @@ -44,23 +44,28 @@ "executions": [ { "name": "001_DeployOriginARMProxyScript", - "timestamp": 1747110973 + "timestampDep": 1747110973, + "timestampGov": 1747110973 }, { "name": "002_DeployOriginARMScript", - "timestamp": 1747907433 + "timestampDep": 1747907433, + "timestampGov": 1747907433 }, { "name": "003_UpgradeOriginARMScriptScript", - "timestamp": 1748603225 + "timestampDep": 1748603225, + "timestampGov": 1748603225 }, { "name": "004_DeployPendleAdaptor", - "timestamp": 1755780926 + "timestampDep": 1755780926, + "timestampGov": 1755780926 }, { "name": "005_UpgradeOriginARMSetBufferScript", - "timestamp": 1755782543 + "timestampDep": 1755782543, + "timestampGov": 1755782543 } ] } diff --git a/build/deployments-17000.json b/build/deployments-17000.json deleted file mode 100644 index 40ecd70b..00000000 --- a/build/deployments-17000.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contracts": [ - { - "implementation": "0x8c7a302e208885ee4658E7422f9E259364cC993b", - "name": "OETH_ARM" - }, - { - "implementation": "0x699092668712E4e94B5b42Fb0aC5dA6209A67394", - "name": "OETH_ARM_IMPL" - } - ], - "executions": [ - { - "name": "001_CoreHolesky", - "timestamp": 1723613808 - } - ] -} diff --git a/script/deploy/Base.s.sol b/script/deploy/Base.s.sol index 04381738..5fef70d8 100644 --- a/script/deploy/Base.s.sol +++ b/script/deploy/Base.s.sol @@ -37,9 +37,10 @@ abstract contract Base { /// Address is computed as the uint256 hash of "Resolver". /// Provides: /// - implementations(name): Get deployed contract address by name - /// - executionExists(name): Check if a script has been run + /// - depTimestamp(name): Get deployment timestamp for a script + /// - govTimestamp(name): Get governance timestamp for a script /// - addContract(name, addr): Register a deployed contract - /// - addExecution(name, timestamp): Mark a script as executed + /// - addExecution(name, depTs, govTs): Record a script execution Resolver internal resolver = Resolver(address(uint160(uint256(keccak256("Resolver"))))); // ==================== Logging Configuration ==================== // @@ -89,6 +90,17 @@ abstract contract Base { vm.resumeTracing(); } + // ==================== Helpers ==================== // + + /// @notice Extracts script name (without extension) from a full file path. + /// @dev Example: "/path/to/015_UpgradeEthenaARMScript.s.sol" -> "015_UpgradeEthenaARMScript" + /// @param fullPath The full filesystem path to a deployment script file + /// @return The script name without directory prefix or file extension + function _extractScriptName(string memory fullPath) internal view returns (string memory) { + string[] memory segments = vm.split(fullPath, "/"); + return vm.split(segments[segments.length - 1], ".")[0]; + } + // ==================== Constructor ==================== // /// @notice Initializes the chain name mappings. diff --git a/script/deploy/DeployManager.s.sol b/script/deploy/DeployManager.s.sol index 7d8c715f..12660b38 100644 --- a/script/deploy/DeployManager.s.sol +++ b/script/deploy/DeployManager.s.sol @@ -31,13 +31,6 @@ contract DeployManager is Base { // Contains the history of deployed contracts and executed scripts. string public deployment; - // Maximum number of recent deployment scripts to process. - // This improves efficiency by skipping older scripts that are already deployed, - // avoiding unnecessary compilation and execution of historical deployment files. - // Scripts are numbered (e.g., 001_, 002_...) and sorted alphabetically, - // so only the last N scripts (most recent) will be considered for deployment. - uint256 public maxDeploymentFiles = 2; - /// @notice Initializes the deployment environment before running scripts. /// @dev Called automatically by Forge before run(). Sets up: /// - Deployment state (FORK_TEST, FORK_DEPLOYING, or REAL_DEPLOYING) @@ -101,8 +94,8 @@ contract DeployManager is Base { /// 1. Load existing deployment history into Resolver /// 2. Determine the correct script folder based on chain ID /// 3. Read all script files from the folder (sorted alphabetically) - /// 4. Process only the last N scripts (controlled by maxDeploymentFiles) - /// 5. For each script: compile, deploy, and execute via _runDeployFile() + /// 4. Skip scripts that are fully executed (deployment + governance) via Resolver + /// 5. For remaining scripts: compile, deploy, and execute via _runDeployFile() /// 6. Save updated deployment history back to JSON function run() external virtual { // Load existing deployment data from JSON file into the Resolver @@ -128,104 +121,85 @@ contract DeployManager is Base { VmSafe.DirEntry[] memory files = vm.readDir(path); vm.resumeTracing(); - // Calculate the starting index to only process the last N files - // If we have more files than maxDeploymentFiles, start from (total - max) - // Otherwise, start from 0 (process all files) - uint256 startIndex = files.length > maxDeploymentFiles ? files.length - maxDeploymentFiles : 0; - - // Calculate how many files we'll actually process - // Either maxDeploymentFiles or total files count, whichever is smaller - uint256 resultSize = files.length > maxDeploymentFiles ? maxDeploymentFiles : files.length; - - // Iterate through the selected files (last N files in alphabetical order) - for (uint256 i; i < resultSize; i++) { - // Split the full file path by "/" to extract the filename - // e.g., "/path/to/script/deploy/mainnet/015_UpgradeEthenaARMScript.sol" - // -> ["path", "to", ..., "015_UpgradeEthenaARMScript.sol"] - string[] memory splitted = vm.split(files[startIndex + i].path, "/"); - string memory onlyName = vm.split(splitted[splitted.length - 1], ".")[0]; - - // Deploy the script contract using vm.deployCode with just the filename - // vm.deployCode compiles and deploys the contract, returning its address - // Then call _runDeployFile to execute the deployment logic + // Iterate through all script files, skipping those that don't need processing. + // Fully executed scripts (both depTimestamp and govTimestamp set and <= block.timestamp) + // are skipped via filename lookup (fast path, no vm.deployCode needed). + // For the few Sonic scripts where the filename differs from the execution name, + // the check returns false and the script falls through to _runDeployFile(), + // which handles it correctly via deployFile.name(). + for (uint256 i = 0; i < files.length; i++) { + if (files[i].isDir) continue; + + string memory scriptName = _extractScriptName(files[i].path); + + uint256 depTs = resolver.depTimestamp(scriptName); + uint256 govTs = resolver.govTimestamp(scriptName); + + // Fast path: skip fully executed scripts (deployed + governance both done) + if (depTs > 0 && govTs > 0 && govTs <= block.timestamp) continue; + + // Deploy the script contract using the explicit artifact path string memory contractName = - string(abi.encodePacked(projectRoot, "/out/", onlyName, ".s.sol/$", onlyName, ".json")); + string(abi.encodePacked(projectRoot, "/out/", scriptName, ".s.sol/$", scriptName, ".json")); _runDeployFile(address(vm.deployCode(contractName))); } - vm.resumeTracing(); // Save all deployment data from Resolver back to JSON file _postDeployment(); } /// @notice Executes a single deployment script with proper state checks. - /// @dev Implements a multi-step validation process: - /// 1. Check if script is marked to skip - /// 2. Check if governance proposal was already executed - /// 3. Check if deployment was already run (in history) - /// 4. Either handle pending governance proposal or run fresh deployment + /// @dev Uses timestamp comparisons to determine script state: + /// - Not deployed (depTs == 0 or depTs > block.timestamp): run full deployment + /// - Deployed + governance done (govTs > 0 and govTs <= block.timestamp): skip + /// - Deployed + governance pending: handle governance proposal /// @param addr The address of the deployed AbstractDeployScript contract function _runDeployFile(address addr) internal { - // Cast the address to AbstractDeployScript interface AbstractDeployScript deployFile = AbstractDeployScript(addr); - - // Skip if the script explicitly sets skip = true - // Useful for temporarily disabling scripts without removing them if (deployFile.skip()) return; - // Skip if the governance proposal for this script was already executed - // This means the script's purpose has been fully accomplished - if (deployFile.proposalExecuted()) return; - - // Get the script's unique name for history lookup string memory deployFileName = deployFile.name(); + vm.label(address(deployFile), deployFileName); - // Check deployment history to see if this script was already run - bool alreadyDeployed = resolver.executionExists(deployFileName); + uint256 depTs = resolver.depTimestamp(deployFileName); + bool alreadyDeployed = depTs > 0 && depTs <= block.timestamp; - // Label the contract address for better trace readability in Forge - vm.label(address(deployFile), deployFileName); + if (!alreadyDeployed) { + deployFile.run(); + return; + } - // At this point, proposalExecuted is false, meaning the governance - // proposal hasn't been finalized yet. Two scenarios: - // - // Scenario A: Script was deployed but proposal is still pending - // -> Only handle the governance proposal (don't re-deploy) - // - // Scenario B: Script was never deployed - // -> Run the full deployment - - if (alreadyDeployed) { - // Scenario A: Deployment exists, just handle governance - log.logSkip(deployFileName, "deployment already executed"); - log.info(string.concat("Handling governance proposal for ", deployFileName)); - deployFile.handleGovernanceProposal(); + uint256 govTs = resolver.govTimestamp(deployFileName); + if (govTs > 0 && govTs <= block.timestamp) { + log.logSkip(deployFileName, "fully executed"); return; } - // Scenario B: Fresh deployment - run the script - deployFile.run(); + log.info(string.concat("Handling governance proposal for ", deployFileName)); + deployFile.handleGovernanceProposal(); } /// @notice Loads deployment history from JSON file into the Resolver. /// @dev Called at the start of run() to populate the Resolver with: /// - Previously deployed contract addresses (for lookups via resolver.implementations()) /// - Previously executed script names (to avoid re-running deployments) + /// All executions are loaded unconditionally; timestamp comparisons against + /// block.timestamp are done at query time in the pre-filter and _runDeployFile. /// Uses pauseTracing modifier to reduce noise in Forge output. function _preDeployment() internal pauseTracing { // Parse the JSON deployment file into structured data Root memory root = abi.decode(vm.parseJson(deployment), (Root)); // Load all deployed contract addresses into the Resolver - // This allows scripts to lookup addresses via resolver.implementations("CONTRACT_NAME") for (uint256 i = 0; i < root.contracts.length; i++) { resolver.addContract(root.contracts[i].name, root.contracts[i].implementation); } - // Load all execution records into the Resolver - // This tracks which scripts have already been run to prevent duplicates + // Load all execution records into the Resolver unconditionally for (uint256 i = 0; i < root.executions.length; i++) { - resolver.addExecution(root.executions[i].name, root.executions[i].timestamp); + resolver.addExecution( + root.executions[i].name, root.executions[i].timestampDep, root.executions[i].timestampGov + ); } } @@ -249,10 +223,12 @@ contract DeployManager is Base { serializedContracts[i] = vm.serializeAddress("c_obj", "implementation", contracts[i].implementation); } - // Serialize each execution as a JSON object: {"name": "...", "timestamp": ...} + // Serialize each execution as a JSON object with governance tracking + // Fields are serialized in alphabetical order for consistent output for (uint256 i = 0; i < executions.length; i++) { vm.serializeString("e_obj", "name", executions[i].name); - serializedExecutions[i] = vm.serializeUint("e_obj", "timestamp", executions[i].timestamp); + vm.serializeUint("e_obj", "timestampDep", executions[i].timestampDep); + serializedExecutions[i] = vm.serializeUint("e_obj", "timestampGov", executions[i].timestampGov); } // Build the root JSON object with both arrays diff --git a/script/deploy/README.md b/script/deploy/README.md index 891cec00..106943f2 100644 --- a/script/deploy/README.md +++ b/script/deploy/README.md @@ -30,8 +30,8 @@ script/deploy/ 2. **DeployManager.run()** executes deployment scripts: - Loads existing deployment history into the Resolver - Reads scripts from the chain-specific folder (e.g., `mainnet/` or `sonic/`) - - Processes only the last N scripts (default: 2) to improve efficiency - - For each script: compiles, deploys, and executes via `_runDeployFile()` + - Skips fully executed scripts (both `timestampDep` and `timestampGov` set) via timestamp checks + - For remaining scripts: compiles, deploys, and executes via `_runDeployFile()` 3. **Each script** (inheriting from AbstractDeployScript): - Runs `_execute()` to deploy contracts @@ -62,7 +62,7 @@ Format: { "name": "LIDO_ARM_IMPL", "implementation": "0x..." } ], "executions": [ - { "name": "001_CoreMainnet", "timestamp": 1723685111 } + { "name": "001_CoreMainnet", "timestampDep": 1723685111, "timestampGov": 1723685111 } ] } ``` @@ -90,9 +90,6 @@ contract $017_UpgradeLidoARM is AbstractDeployScript("017_UpgradeLidoARM") { // Set to true to skip this script bool public constant override skip = false; - // Set to true once governance proposal is executed on-chain - bool public constant override proposalExecuted = false; - function _execute() internal override { // 1. Get previously deployed contracts address proxy = resolver.implementations("LIDO_ARM"); @@ -127,7 +124,6 @@ contract $017_UpgradeLidoARM is AbstractDeployScript("017_UpgradeLidoARM") { | `_buildGovernanceProposal()` | Define governance actions | | `_fork()` | Post-deployment verification (fork mode only) | | `skip()` | Return `true` to skip this script | -| `proposalExecuted()` | Return `true` when governance is complete | ### 4. Resolver Usage @@ -189,7 +185,7 @@ govProposal.action( ## Tips -1. **Always check `skip` and `proposalExecuted`** - Set `proposalExecuted = true` once governance passes to prevent re-execution. +1. **Use `skip()` to disable scripts** - Override `skip()` to return `true` to temporarily disable a script. Governance completion is tracked automatically via `timestampGov` in the deployment JSON. 2. **Use descriptive contract names** - Names like `LIDO_ARM_IMPL` are clearer than `IMPL_V2`. @@ -197,6 +193,6 @@ govProposal.action( 4. **Scripts are processed in order** - Name files with numeric prefixes (001_, 002_, etc.). -5. **Only the last N scripts run** - By default, only the 2 most recent scripts are processed. Older scripts are skipped if already in deployment history. +5. **Fully executed scripts are skipped** - Scripts with both `timestampDep` and `timestampGov` set in deployment history are skipped automatically. 6. **Reference the example** - See `mainnet/000_Example.s.sol` for a comprehensive template. diff --git a/script/deploy/UpdateGovernance.s.sol b/script/deploy/UpdateGovernance.s.sol new file mode 100644 index 00000000..6ddb0817 --- /dev/null +++ b/script/deploy/UpdateGovernance.s.sol @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.23; + +// Foundry +import {Vm} from "forge-std/Vm.sol"; +import {VmSafe} from "forge-std/Vm.sol"; + +// Helpers +import {Logger} from "script/deploy/helpers/Logger.sol"; +import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; +import {GovHelper, IGovernance} from "script/deploy/helpers/GovHelper.sol"; +import {State, Execution, Contract, Root, GovProposal} from "script/deploy/helpers/DeploymentTypes.sol"; + +// Script Base +import {Base} from "script/deploy/Base.s.sol"; + +// Utils +import {Mainnet} from "src/contracts/utils/Addresses.sol"; + +/// @title UpdateGovernance +/// @notice CLI tool to check on-chain governance state and update deployment JSON. +/// @dev Forks mainnet at latest block, iterates over executions with timestampGov == 0, +/// checks if their governance proposals have been executed on-chain, and updates the JSON. +/// +/// Usage: make update-governance +contract UpdateGovernance is Base { + using Logger for bool; + + // Raw JSON content of the deployment file + string public deployment; + + /// @notice Initializes the governance update environment. + function setUp() external { + log = true; + state = State.FORK_TEST; + + log.header("Update Governance Timestamps"); + + // Build path to chain-specific deployment file + string memory deployFilePath = getChainDeploymentFilePath(); + require(vm.isFile(deployFilePath), "Deployment file not found"); + deployment = vm.readFile(deployFilePath); + + // Deploy the Resolver contract + deployResolver(); + } + + /// @notice Main entry point — checks governance state and updates JSON. + function run() external { + // Parse the JSON deployment file into structured data + Root memory root; + { + vm.pauseTracing(); + root = abi.decode(vm.parseJson(deployment), (Root)); + vm.resumeTracing(); + } + + // Load all data into Resolver + vm.pauseTracing(); + for (uint256 i = 0; i < root.contracts.length; i++) { + resolver.addContract(root.contracts[i].name, root.contracts[i].implementation); + } + for (uint256 i = 0; i < root.executions.length; i++) { + resolver.addExecution( + root.executions[i].name, root.executions[i].timestampDep, root.executions[i].timestampGov + ); + } + vm.resumeTracing(); + + // Read deployment script files + string memory path; + if (block.chainid == 1) { + path = string(abi.encodePacked(projectRoot, "/script/deploy/mainnet/")); + } else if (block.chainid == 146) { + path = string(abi.encodePacked(projectRoot, "/script/deploy/sonic/")); + } else { + revert("Unsupported chain"); + } + + vm.pauseTracing(); + VmSafe.DirEntry[] memory files = vm.readDir(path); + vm.resumeTracing(); + + IGovernance governance = IGovernance(Mainnet.GOVERNOR_SIX); + bool anyUpdated = false; + + // Check each execution with pending governance + for (uint256 i = 0; i < root.executions.length; i++) { + if (root.executions[i].timestampGov != 0) continue; + + string memory execName = root.executions[i].name; + log.info(string.concat("Checking governance for: ", execName)); + + // Find and deploy the corresponding script file + address scriptAddr = _findAndDeployScript(files, execName); + if (scriptAddr == address(0)) { + log.warn(string.concat("Script file not found for: ", execName)); + continue; + } + + // Build the governance proposal (without simulating) + AbstractDeployScript deployFile = AbstractDeployScript(scriptAddr); + GovProposal memory prop; + try deployFile.buildGovernanceProposal() returns (GovProposal memory p) { + prop = p; + } catch { + log.warn(string.concat("Failed to build proposal for: ", execName)); + continue; + } + + // If no governance actions, mark as complete + if (prop.actions.length == 0) { + root.executions[i].timestampGov = root.executions[i].timestampDep; + resolver.addGovernanceTimestamp(execName, root.executions[i].timestampDep); + log.success(string.concat("No governance needed for: ", execName)); + anyUpdated = true; + continue; + } + + // Compute proposal ID and check on-chain state + uint256 proposalId = GovHelper.id(prop); + IGovernance.ProposalState propState = governance.state(proposalId); + log.logKeyValue(" Proposal ID", proposalId); + log.logKeyValue(" Proposal state", _stateToString(propState)); + + if (propState == IGovernance.ProposalState.Executed) { + root.executions[i].timestampGov = block.timestamp; + resolver.addGovernanceTimestamp(execName, block.timestamp); + log.success(string.concat("Governance executed for: ", execName)); + anyUpdated = true; + } else { + log.info(string.concat("Governance still pending for: ", execName)); + } + } + + if (!anyUpdated) { + log.info("No governance timestamps to update"); + return; + } + + // Write updated JSON + _writeDeploymentJson(root); + log.success("Deployment JSON updated"); + } + + // ==================== Helper Functions ==================== // + + /// @notice Finds and deploys a script by its execution name. + function _findAndDeployScript(VmSafe.DirEntry[] memory files, string memory execName) internal returns (address) { + vm.pauseTracing(); + for (uint256 i = 0; i < files.length; i++) { + if (files[i].isDir) continue; + + string memory scriptName = _extractScriptName(files[i].path); + + // Deploy the script and check if its execution name matches + string memory contractName = + string(abi.encodePacked(projectRoot, "/out/", scriptName, ".s.sol/$", scriptName, ".json")); + try vm.deployCode(contractName) returns (address addr) { + AbstractDeployScript script = AbstractDeployScript(addr); + if (keccak256(bytes(script.name())) == keccak256(bytes(execName))) { + vm.resumeTracing(); + return addr; + } + } catch {} + } + vm.resumeTracing(); + return address(0); + } + + /// @notice Writes deployment data back to JSON. + function _writeDeploymentJson(Root memory root) internal { + vm.pauseTracing(); + + Contract[] memory contracts_ = root.contracts; + Execution[] memory executions = root.executions; + + string[] memory serializedContracts = new string[](contracts_.length); + string[] memory serializedExecutions = new string[](executions.length); + + for (uint256 i = 0; i < contracts_.length; i++) { + vm.serializeString("c_obj", "name", contracts_[i].name); + serializedContracts[i] = vm.serializeAddress("c_obj", "implementation", contracts_[i].implementation); + } + + for (uint256 i = 0; i < executions.length; i++) { + vm.serializeString("e_obj", "name", executions[i].name); + vm.serializeUint("e_obj", "timestampDep", executions[i].timestampDep); + serializedExecutions[i] = vm.serializeUint("e_obj", "timestampGov", executions[i].timestampGov); + } + + vm.serializeString("root", "contracts", serializedContracts); + string memory finalJson = vm.serializeString("root", "executions", serializedExecutions); + + vm.writeFile(getChainDeploymentFilePath(), finalJson); + vm.resumeTracing(); + } + + /// @notice Deploys the Resolver contract to a deterministic address. + function deployResolver() public { + vm.pauseTracing(); + bytes memory resolverCode = vm.getDeployedCode("Resolver.sol:Resolver"); + vm.etch(address(resolver), resolverCode); + resolver.setState(state); + vm.label(address(resolver), "Resolver"); + vm.resumeTracing(); + } + + /// @notice Returns the path to the main deployment file for the current chain. + function getChainDeploymentFilePath() public view returns (string memory) { + string memory chainIdStr = vm.toString(block.chainid); + return string(abi.encodePacked(projectRoot, "/build/deployments-", chainIdStr, ".json")); + } + + /// @notice Converts governance proposal state to string. + function _stateToString(IGovernance.ProposalState _state) internal pure returns (string memory) { + if (_state == IGovernance.ProposalState.Pending) return "Pending"; + if (_state == IGovernance.ProposalState.Active) return "Active"; + if (_state == IGovernance.ProposalState.Canceled) return "Canceled"; + if (_state == IGovernance.ProposalState.Defeated) return "Defeated"; + if (_state == IGovernance.ProposalState.Succeeded) return "Succeeded"; + if (_state == IGovernance.ProposalState.Queued) return "Queued"; + if (_state == IGovernance.ProposalState.Expired) return "Expired"; + if (_state == IGovernance.ProposalState.Executed) return "Executed"; + return "Unknown"; + } +} diff --git a/script/deploy/helpers/AbstractDeployScript.s.sol b/script/deploy/helpers/AbstractDeployScript.s.sol index 1fe2d078..a80f598d 100644 --- a/script/deploy/helpers/AbstractDeployScript.s.sol +++ b/script/deploy/helpers/AbstractDeployScript.s.sol @@ -28,7 +28,6 @@ import {Base} from "script/deploy/Base.s.sol"; /// - _buildGovernanceProposal(): Define governance actions (optional) /// - _fork(): Post-deployment fork testing logic (optional) /// - skip(): Return true to skip this script (optional) -/// - proposalExecuted(): Return true if governance already executed (optional) /// /// Execution Flow (run()): /// 1. Get state from Resolver @@ -137,6 +136,8 @@ abstract contract AbstractDeployScript is Base { // Check if there are any governance actions to process if (govProposal.actions.length == 0) { + // No governance needed - mark governance as complete immediately + resolver.addGovernanceTimestamp(name, block.timestamp); log.info("No governance proposal to handle"); return; } else { @@ -185,10 +186,12 @@ abstract contract AbstractDeployScript is Base { } /// @notice Persists all recorded contracts to the Resolver and marks script as executed. - /// @dev Called automatically at the end of run(). + /// @dev Called automatically at the end of run() (Step 6, before governance in Step 7). /// Iterates through all contracts added via _recordDeployment() and /// registers them in the global Resolver for cross-script access. - /// Also records this script's execution to prevent re-runs. + /// Also records this script's execution with timestampGov = 0 (pending). + /// Governance timestamp is updated later: either immediately by run() if no + /// governance actions exist, or by UpdateGovernance once executed on-chain. function _storeDeployedContract() internal virtual { // Persist each deployed contract to the Resolver for (uint256 i = 0; i < contracts.length; i++) { @@ -196,7 +199,13 @@ abstract contract AbstractDeployScript is Base { } // Mark this script as executed (prevents DeployManager from re-running it) - resolver.addExecution(name, block.timestamp); + // If no governance actions, mark governance as complete immediately + // If governance actions exist, leave timestampGov as 0 (pending) + // Note: _buildGovernanceProposal() is called AFTER this function in run(), + // so we cannot check govProposal.actions.length here. Instead, governance + // timestamp will be determined by the JSON data / UpdateGovernance tool. + // For fresh deployments, timestampGov starts at 0. + resolver.addExecution(name, block.timestamp, 0); } // ==================== Virtual Hooks (Override in Child Contracts) ==================== // @@ -252,16 +261,17 @@ abstract contract AbstractDeployScript is Base { /// @return True to skip this script, false to execute function skip() external view virtual returns (bool) {} - /// @notice Checks if the governance proposal for this script has been executed. - /// @dev Override to return true when the on-chain proposal is complete. - /// When true, DeployManager will skip this script entirely. - /// Useful for scripts that deploy + create governance proposals. - /// @return True if governance proposal was executed on-chain - function proposalExecuted() external view virtual returns (bool) {} + /// @notice Builds and returns the governance proposal without simulating. + /// @dev Called by UpdateGovernance to compute proposal IDs for on-chain checks. + /// @return The built governance proposal + function buildGovernanceProposal() external virtual returns (GovProposal memory) { + _buildGovernanceProposal(); + return govProposal; + } /// @notice Handles governance proposal when deployment was already done. - /// @dev Called by DeployManager when script is in history but proposalExecuted() is false. - /// Override to implement proposal resubmission or status checking logic. + /// @dev Called by DeployManager when script is in history but governance is still pending. + /// Rebuilds and simulates the governance proposal. function handleGovernanceProposal() external virtual { _buildGovernanceProposal(); log.simulate(govProposal); diff --git a/script/deploy/helpers/DeploymentTypes.sol b/script/deploy/helpers/DeploymentTypes.sol index abad26a3..1c49fb5c 100644 --- a/script/deploy/helpers/DeploymentTypes.sol +++ b/script/deploy/helpers/DeploymentTypes.sol @@ -41,13 +41,19 @@ enum State { /// @notice Records a deployment script execution for history tracking. /// @dev Stored in the Resolver to prevent re-running completed scripts. /// Persisted to JSON for cross-session continuity. +/// Fields MUST be in alphabetical order (Foundry JSON parsing requirement). struct Execution { /// @notice The unique name of the deployment script. /// @dev Format: "NNN_DescriptiveName" (e.g., "015_UpgradeEthenaARMScript") string name; - /// @notice Block timestamp when the script was executed. - /// @dev Used for ordering and auditing purposes. - uint256 timestamp; + /// @notice Block timestamp when the script's _execute() ran (contracts deployed). + /// @dev Used for ordering, auditing, and historical-block fork filtering. + uint256 timestampDep; + /// @notice Block timestamp when governance was executed on-chain. + /// @dev 0 = governance pending (or script has no proposal yet). + /// == timestampDep = no governance needed (script fully complete at deploy time). + /// > 0 && != timestampDep = governance executed at a later time. + uint256 timestampGov; } /// @notice Represents a deployed contract's address and identifier. diff --git a/script/deploy/helpers/GovHelper.sol b/script/deploy/helpers/GovHelper.sol index dfa98a6c..eef64f70 100644 --- a/script/deploy/helpers/GovHelper.sol +++ b/script/deploy/helpers/GovHelper.sol @@ -195,7 +195,7 @@ library GovHelper { /// /// @param log Whether logging is enabled /// @param prop The proposal to simulate - function simulate(bool log, GovProposal memory prop) internal { + function simulate(bool log, GovProposal memory prop) internal restoreBlockAndTimestamp { // ===== Setup: Label addresses for trace readability ===== address govMultisig = Mainnet.GOV_MULTISIG; vm.label(govMultisig, "Gov Multisig"); @@ -296,6 +296,14 @@ library GovHelper { } } + modifier restoreBlockAndTimestamp() { + uint256 originalBlock = block.number; + uint256 originalTimestamp = block.timestamp; + _; + vm.roll(originalBlock); + vm.warp(originalTimestamp); + } + // ==================== Utility Functions ==================== // /// @notice Converts a proposal state enum to a human-readable string. diff --git a/script/deploy/helpers/Resolver.sol b/script/deploy/helpers/Resolver.sol index 6d4c267d..c9b91f12 100644 --- a/script/deploy/helpers/Resolver.sol +++ b/script/deploy/helpers/Resolver.sol @@ -34,21 +34,35 @@ contract Resolver { // Enables O(1) lookups and updates for existing contracts mapping(string => Position) public inContracts; - // Quick lookup to check if a deployment script was already executed - // Key: script name (e.g., "015_UpgradeEthenaARMScript") - mapping(string => bool) public executionExists; - // Quick lookup for deployed contract addresses by name // Key: contract name (e.g., "LIDO_ARM", "ETHENA_ARM_IMPL") // Value: deployed address mapping(string => address) public implementations; + // Quick lookup for execution index by name (for governance timestamp updates) + // Key: script name, Value: index in executions array + mapping(string => uint256) public executionIndex; + + // Quick lookup for deployment timestamp by script name + // 0 means never deployed + mapping(string => uint256) public depTimestamp; + + // Quick lookup for governance timestamp by script name + // 0 means governance not yet executed + mapping(string => uint256) public govTimestamp; + // ==================== Events ==================== // /// @notice Emitted when a new execution record is added /// @param name The name of the deployment script - /// @param timestamp The block timestamp when the script was executed - event ExecutionAdded(string name, uint256 timestamp); + /// @param timestampDep The block timestamp when the script was executed + /// @param timestampGov The timestamp when governance was executed (0 if pending) + event ExecutionAdded(string name, uint256 timestampDep, uint256 timestampGov); + + /// @notice Emitted when a governance timestamp is updated for an existing execution + /// @param name The name of the deployment script + /// @param timestampGov The timestamp when governance was executed + event GovernanceTimestampUpdated(string name, uint256 timestampGov); /// @notice Emitted when a contract address is registered or updated /// @param name The identifier for the contract @@ -85,21 +99,29 @@ contract Resolver { // ==================== Execution Management ==================== // /// @notice Records that a deployment script has been executed. - /// @dev Prevents duplicate executions by reverting if already recorded. - /// Called by deployment scripts after successful execution. + /// @dev Called by deployment scripts after successful execution, or by DeployManager + /// when loading execution history from JSON. /// @param name The unique name of the deployment script (e.g., "015_UpgradeEthenaARMScript") - /// @param timestamp The block timestamp of execution - function addExecution(string memory name, uint256 timestamp) external { - // Prevent duplicate execution records - require(!executionExists[name], "Execution already exists"); - - // Add to array for JSON serialization - executions.push(Execution({name: name, timestamp: timestamp})); + /// @param _timestampDep The block timestamp of execution + /// @param _timestampGov The timestamp when governance was executed (0 if pending) + function addExecution(string memory name, uint256 _timestampDep, uint256 _timestampGov) external { + executionIndex[name] = executions.length; + executions.push(Execution({name: name, timestampDep: _timestampDep, timestampGov: _timestampGov})); + depTimestamp[name] = _timestampDep; + govTimestamp[name] = _timestampGov; + + emit ExecutionAdded(name, _timestampDep, _timestampGov); + } - // Mark as executed for quick lookups - executionExists[name] = true; + /// @notice Updates the governance timestamp for an existing execution. + /// @dev Called when a governance proposal is confirmed as executed on-chain. + /// @param name The unique name of the deployment script + /// @param _timestampGov The timestamp when governance was executed + function addGovernanceTimestamp(string memory name, uint256 _timestampGov) external { + executions[executionIndex[name]].timestampGov = _timestampGov; + govTimestamp[name] = _timestampGov; - emit ExecutionAdded(name, timestamp); + emit GovernanceTimestampUpdated(name, _timestampGov); } // ==================== View Functions ==================== // @@ -113,7 +135,7 @@ contract Resolver { /// @notice Returns all execution records. /// @dev Used by DeployManager._postDeployment() to serialize to JSON. - /// @return Array of all Execution structs (name + timestamp) + /// @return Array of all Execution structs (name + timestampDep + timestampGov) function getExecutions() external view returns (Execution[] memory) { return executions; } diff --git a/script/deploy/mainnet/000_Example.s.sol b/script/deploy/mainnet/000_Example.s.sol index 89b9992e..5ba9f2b1 100644 --- a/script/deploy/mainnet/000_Example.s.sol +++ b/script/deploy/mainnet/000_Example.s.sol @@ -55,11 +55,6 @@ contract $000_Example is AbstractDeployScript("000_Example") { /// DeployManager checks this before running the script. bool public constant override skip = true; // Skip this example by default - /// @notice Indicates if the governance proposal was already executed on-chain. - /// @dev Override this to return true when the on-chain proposal is complete. - /// This prevents the script from running again after governance execution. - bool public constant override proposalExecuted = false; - // ==================== State Variables ==================== // // Declare variables here for contracts deployed in _execute() diff --git a/script/deploy/mainnet/003_UpgradeLidoARMScript.s.sol b/script/deploy/mainnet/003_UpgradeLidoARMScript.s.sol index d44b9d61..7e1568eb 100644 --- a/script/deploy/mainnet/003_UpgradeLidoARMScript.s.sol +++ b/script/deploy/mainnet/003_UpgradeLidoARMScript.s.sol @@ -12,9 +12,7 @@ import {IERC20, LegacyAMM} from "contracts/Interfaces.sol"; // Deployment import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; -contract $003_UpgradeLidoARMMainnetScript is AbstractDeployScript("003_UpgradeLidoARMScript") { - bool public override proposalExecuted = true; - +contract $003_UpgradeLidoARMScript is AbstractDeployScript("003_UpgradeLidoARMScript") { Proxy lidoARMProxy; Proxy capManProxy; LidoARM lidoARMImpl; diff --git a/script/deploy/mainnet/004_UpdateCrossPriceScript.s.sol b/script/deploy/mainnet/004_UpdateCrossPriceScript.s.sol index 65a2dfa6..7ce4450c 100644 --- a/script/deploy/mainnet/004_UpdateCrossPriceScript.s.sol +++ b/script/deploy/mainnet/004_UpdateCrossPriceScript.s.sol @@ -5,11 +5,9 @@ pragma solidity 0.8.23; import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; import {GovHelper, GovProposal} from "script/deploy/helpers/GovHelper.sol"; -contract $004_UpdateCrossPriceMainnetScript is AbstractDeployScript("004_UpdateCrossPriceScript") { +contract $004_UpdateCrossPriceScript is AbstractDeployScript("004_UpdateCrossPriceScript") { using GovHelper for GovProposal; - bool public override proposalExecuted = true; - function _buildGovernanceProposal() internal override { govProposal.setDescription("Update Cross Price for Lido ARM"); diff --git a/script/deploy/mainnet/005_RegisterLidoWithdrawalsScript.s.sol b/script/deploy/mainnet/005_RegisterLidoWithdrawalsScript.s.sol index c0a91eef..abb02951 100644 --- a/script/deploy/mainnet/005_RegisterLidoWithdrawalsScript.s.sol +++ b/script/deploy/mainnet/005_RegisterLidoWithdrawalsScript.s.sol @@ -12,8 +12,6 @@ import {GovHelper, GovProposal} from "script/deploy/helpers/GovHelper.sol"; contract $005_RegisterLidoWithdrawalsScript is AbstractDeployScript("005_RegisterLidoWithdrawalsScript") { using GovHelper for GovProposal; - bool public override proposalExecuted = true; - function _execute() internal override { // 1. Deploy new Lido ARM implementation uint256 claimDelay = 10 minutes; diff --git a/script/deploy/mainnet/006_ChangeFeeCollector.s.sol b/script/deploy/mainnet/006_ChangeFeeCollector.s.sol index 63214b1e..23bc46db 100644 --- a/script/deploy/mainnet/006_ChangeFeeCollector.s.sol +++ b/script/deploy/mainnet/006_ChangeFeeCollector.s.sol @@ -8,11 +8,9 @@ import {Mainnet} from "contracts/utils/Addresses.sol"; import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; import {GovHelper, GovProposal} from "script/deploy/helpers/GovHelper.sol"; -contract $006_ChangeFeeCollectorScript is AbstractDeployScript("006_ChangeFeeCollector") { +contract $006_ChangeFeeCollector is AbstractDeployScript("006_ChangeFeeCollector") { using GovHelper for GovProposal; - bool public override proposalExecuted = true; - function _buildGovernanceProposal() internal override { govProposal.setDescription("Change fee collector"); diff --git a/script/deploy/mainnet/007_UpgradeLidoARMMorphoScript.s.sol b/script/deploy/mainnet/007_UpgradeLidoARMMorphoScript.s.sol index 4e4237c8..a41ffc39 100644 --- a/script/deploy/mainnet/007_UpgradeLidoARMMorphoScript.s.sol +++ b/script/deploy/mainnet/007_UpgradeLidoARMMorphoScript.s.sol @@ -14,8 +14,6 @@ import {GovHelper, GovProposal} from "script/deploy/helpers/GovHelper.sol"; contract $007_UpgradeLidoARMMorphoScript is AbstractDeployScript("007_UpgradeLidoARMMorphoScript") { using GovHelper for GovProposal; - bool public override proposalExecuted = true; - function _execute() internal override { // 1. Deploy new Lido implementation uint256 claimDelay = 10 minutes; diff --git a/script/deploy/mainnet/008_DeployPendleAdaptor.s.sol b/script/deploy/mainnet/008_DeployPendleAdaptor.s.sol index 64c8d330..7e86201f 100644 --- a/script/deploy/mainnet/008_DeployPendleAdaptor.s.sol +++ b/script/deploy/mainnet/008_DeployPendleAdaptor.s.sol @@ -8,8 +8,6 @@ import {PendleOriginARMSY} from "contracts/pendle/PendleOriginARMSY.sol"; import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; contract $008_DeployPendleAdaptor is AbstractDeployScript("008_DeployPendleAdaptor") { - bool public override proposalExecuted = true; - function _execute() internal override { // 1. Deploy PendleOriginARMSY PendleOriginARMSY sy = diff --git a/script/deploy/mainnet/009_UpgradeLidoARMSetBufferScript.s.sol b/script/deploy/mainnet/009_UpgradeLidoARMSetBufferScript.s.sol index 5ab81301..7270e3a4 100644 --- a/script/deploy/mainnet/009_UpgradeLidoARMSetBufferScript.s.sol +++ b/script/deploy/mainnet/009_UpgradeLidoARMSetBufferScript.s.sol @@ -12,8 +12,6 @@ import {GovHelper, GovProposal} from "script/deploy/helpers/GovHelper.sol"; contract $009_UpgradeLidoARMSetBufferScript is AbstractDeployScript("009_UpgradeLidoARMSetBufferScript") { using GovHelper for GovProposal; - bool public override proposalExecuted = true; - function _execute() internal override { // 1. Deploy new Lido implementation uint256 claimDelay = 10 minutes; diff --git a/script/deploy/mainnet/010_UpgradeLidoARMAssetScript.s.sol b/script/deploy/mainnet/010_UpgradeLidoARMAssetScript.s.sol index b2f6595d..52ed23bd 100644 --- a/script/deploy/mainnet/010_UpgradeLidoARMAssetScript.s.sol +++ b/script/deploy/mainnet/010_UpgradeLidoARMAssetScript.s.sol @@ -13,8 +13,6 @@ import {GovHelper, GovProposal} from "script/deploy/helpers/GovHelper.sol"; contract $010_UpgradeLidoARMAssetScript is AbstractDeployScript("010_UpgradeLidoARMAssetScript") { using GovHelper for GovProposal; - bool public override proposalExecuted = true; - function _execute() internal override { // 1. Deploy new Lido implementation uint256 claimDelay = 10 minutes; diff --git a/script/deploy/mainnet/011_DeployEtherFiARMScript.s.sol b/script/deploy/mainnet/011_DeployEtherFiARMScript.s.sol index 896c1cae..5c5c59fb 100644 --- a/script/deploy/mainnet/011_DeployEtherFiARMScript.s.sol +++ b/script/deploy/mainnet/011_DeployEtherFiARMScript.s.sol @@ -15,8 +15,6 @@ import {Abstract4626MarketWrapper} from "contracts/markets/Abstract4626MarketWra import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; contract $011_DeployEtherFiARMScript is AbstractDeployScript("011_DeployEtherFiARMScript") { - bool public override proposalExecuted = true; - function _execute() internal override { // 1. Deploy new ARM proxy contract Proxy armProxy = new Proxy(); diff --git a/script/deploy/mainnet/012_UpgradeEtherFiARMScript.s.sol b/script/deploy/mainnet/012_UpgradeEtherFiARMScript.s.sol index 402fb2ff..7b5dc702 100644 --- a/script/deploy/mainnet/012_UpgradeEtherFiARMScript.s.sol +++ b/script/deploy/mainnet/012_UpgradeEtherFiARMScript.s.sol @@ -10,8 +10,6 @@ import {EtherFiARM} from "contracts/EtherFiARM.sol"; import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; contract $012_UpgradeEtherFiARMScript is AbstractDeployScript("012_UpgradeEtherFiARMScript") { - bool public override proposalExecuted = true; - EtherFiARM etherFiARMImpl; function _execute() internal override { diff --git a/script/deploy/mainnet/013_UpgradeOETHARMScript.s.sol b/script/deploy/mainnet/013_UpgradeOETHARMScript.s.sol index 46797d18..a5382779 100644 --- a/script/deploy/mainnet/013_UpgradeOETHARMScript.s.sol +++ b/script/deploy/mainnet/013_UpgradeOETHARMScript.s.sol @@ -16,8 +16,6 @@ import {GovHelper, GovProposal} from "script/deploy/helpers/GovHelper.sol"; contract $013_UpgradeOETHARMScript is AbstractDeployScript("013_UpgradeOETHARMScript") { using GovHelper for GovProposal; - bool public override proposalExecuted = true; - function _execute() internal override { // 1. Deploy new Origin implementation uint256 claimDelay = 10 minutes; @@ -42,6 +40,7 @@ contract $013_UpgradeOETHARMScript is AbstractDeployScript("013_UpgradeOETHARMSc govProposal.setDescription("Update OETH ARM to use Origin ARM contract"); // 1. Transfer OETH out of the existing OETH ARM, to have a clean assets per share ratio. + require(resolver.implementations("OETH_ARM") != address(0), "OETH_ARM not found in Resolver"); uint256 balanceOETH = IERC20(Mainnet.OETH).balanceOf(resolver.implementations("OETH_ARM")); govProposal.action( resolver.implementations("OETH_ARM"), @@ -74,6 +73,7 @@ contract $013_UpgradeOETHARMScript is AbstractDeployScript("013_UpgradeOETHARMSc ); // 5. Upgrade OETH ARM to OriginARM and call initialize + require(resolver.implementations("OETH_ARM_IMPL") != address(0), "OETH_ARM_IMPL not found in Resolver"); govProposal.action( resolver.implementations("OETH_ARM"), "upgradeToAndCall(address,bytes)", @@ -83,6 +83,7 @@ contract $013_UpgradeOETHARMScript is AbstractDeployScript("013_UpgradeOETHARMSc // 6. Add Morpho Market as an active market address[] memory markets = new address[](1); markets[0] = resolver.implementations("MORPHO_MARKET_ORIGIN"); + require(markets[0] != address(0), "MORPHO_MARKET_ORIGIN not found in Resolver"); govProposal.action(resolver.implementations("OETH_ARM"), "addMarkets(address[])", abi.encode(markets)); // 7. Set Morpho Market as the active market diff --git a/script/deploy/mainnet/014_DeployEthenaARMScript.s.sol b/script/deploy/mainnet/014_DeployEthenaARMScript.s.sol index b1675c00..f89db4b8 100644 --- a/script/deploy/mainnet/014_DeployEthenaARMScript.s.sol +++ b/script/deploy/mainnet/014_DeployEthenaARMScript.s.sol @@ -13,8 +13,6 @@ import {IWETH, IStakedUSDe} from "contracts/Interfaces.sol"; import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; contract $014_DeployEthenaARMScript is AbstractDeployScript("014_DeployEthenaARMScript") { - bool public override proposalExecuted = true; - uint256 public constant MAX_UNSTAKERS = 42; Proxy armProxy; diff --git a/script/deploy/mainnet/015_UpgradeEthenaARMScript.s.sol b/script/deploy/mainnet/015_UpgradeEthenaARMScript.s.sol index 9d687e2f..42fa5933 100644 --- a/script/deploy/mainnet/015_UpgradeEthenaARMScript.s.sol +++ b/script/deploy/mainnet/015_UpgradeEthenaARMScript.s.sol @@ -10,8 +10,6 @@ import {EthenaARM} from "contracts/EthenaARM.sol"; import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; contract $015_UpgradeEthenaARMScript is AbstractDeployScript("015_UpgradeEthenaARMScript") { - bool public override proposalExecuted = true; - EthenaARM armImpl; function _execute() internal override { diff --git a/script/deploy/mainnet/016_UpgradeLidoARMCrossPriceScript.s.sol b/script/deploy/mainnet/016_UpgradeLidoARMCrossPriceScript.s.sol index 4a00cba4..ad38b855 100644 --- a/script/deploy/mainnet/016_UpgradeLidoARMCrossPriceScript.s.sol +++ b/script/deploy/mainnet/016_UpgradeLidoARMCrossPriceScript.s.sol @@ -8,8 +8,6 @@ import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s contract $016_UpgradeLidoARMCrossPriceScript is AbstractDeployScript("016_UpgradeLidoARMCrossPriceScript") { using GovHelper for GovProposal; - bool public override proposalExecuted = true; - function _execute() internal override {} function _buildGovernanceProposal() internal override { diff --git a/script/deploy/mainnet/017_UpgradeLidoARMScript.s.sol b/script/deploy/mainnet/017_UpgradeLidoARMScript.s.sol index dc37b61e..470b041b 100644 --- a/script/deploy/mainnet/017_UpgradeLidoARMScript.s.sol +++ b/script/deploy/mainnet/017_UpgradeLidoARMScript.s.sol @@ -15,8 +15,6 @@ import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s contract $017_UpgradeLidoARMScript is AbstractDeployScript("017_UpgradeLidoARMScript") { using GovHelper for GovProposal; - bool public override proposalExecuted = false; - Proxy lidoARMProxy; Proxy capManProxy; LidoARM lidoARMImpl; diff --git a/script/deploy/sonic/001_DeployOriginARMProxy.s.sol b/script/deploy/sonic/001_DeployOriginARMProxy.s.sol index 44a0dc8e..23a541ea 100644 --- a/script/deploy/sonic/001_DeployOriginARMProxy.s.sol +++ b/script/deploy/sonic/001_DeployOriginARMProxy.s.sol @@ -7,9 +7,7 @@ import {Proxy} from "contracts/Proxy.sol"; // Deployment import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; -contract $001_DeployOriginARMProxyScript is AbstractDeployScript("001_DeployOriginARMProxyScript") { - bool public override proposalExecuted = true; - +contract $001_DeployOriginARMProxy is AbstractDeployScript("001_DeployOriginARMProxyScript") { function _execute() internal override { // 1. Deploy proxy for the Origin ARM Proxy originARMProxy = new Proxy(); diff --git a/script/deploy/sonic/002_DeployOriginARM.s.sol b/script/deploy/sonic/002_DeployOriginARM.s.sol index c7dcf81a..1815183c 100644 --- a/script/deploy/sonic/002_DeployOriginARM.s.sol +++ b/script/deploy/sonic/002_DeployOriginARM.s.sol @@ -14,9 +14,7 @@ import {SonicHarvester} from "contracts/SonicHarvester.sol"; // Deployment import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; -contract $002_DeployOriginARMScript is AbstractDeployScript("002_DeployOriginARMScript") { - bool public override proposalExecuted = true; - +contract $002_DeployOriginARM is AbstractDeployScript("002_DeployOriginARMScript") { Proxy originARMProxy; function _execute() internal override { diff --git a/script/deploy/sonic/003_UpgradeOriginARM.s.sol b/script/deploy/sonic/003_UpgradeOriginARM.s.sol index d77c5522..12714d17 100644 --- a/script/deploy/sonic/003_UpgradeOriginARM.s.sol +++ b/script/deploy/sonic/003_UpgradeOriginARM.s.sol @@ -11,9 +11,7 @@ import {SonicHarvester} from "contracts/SonicHarvester.sol"; // Deployment imports import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; -contract $003_UpgradeOriginARMScript is AbstractDeployScript("003_UpgradeOriginARMScript") { - bool public override proposalExecuted = true; - +contract $003_UpgradeOriginARM is AbstractDeployScript("003_UpgradeOriginARMScript") { SonicHarvester public harvesterImpl; OriginARM public originARMImpl; SiloMarket public silo_Varlamore_S_MarketImpl; diff --git a/script/deploy/sonic/004_DeployPendleAdaptor.s.sol b/script/deploy/sonic/004_DeployPendleAdaptor.s.sol index 1be5d725..a8cd263d 100644 --- a/script/deploy/sonic/004_DeployPendleAdaptor.s.sol +++ b/script/deploy/sonic/004_DeployPendleAdaptor.s.sol @@ -7,9 +7,7 @@ import {PendleOriginARMSY} from "contracts/pendle/PendleOriginARMSY.sol"; // Deployment imports import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; -contract $004_DeployPendleAdaptorSonic is AbstractDeployScript("004_DeployPendleAdaptor") { - bool public override proposalExecuted = false; - +contract $004_DeployPendleAdaptor is AbstractDeployScript("004_DeployPendleAdaptor") { function _execute() internal override { // 1. Deploy PendleOriginARMSY PendleOriginARMSY sy = diff --git a/script/deploy/sonic/005_UpgradeOriginARMSetBufferScript.s.sol b/script/deploy/sonic/005_UpgradeOriginARMSetBufferScript.s.sol index db9b9a26..d0d21eba 100644 --- a/script/deploy/sonic/005_UpgradeOriginARMSetBufferScript.s.sol +++ b/script/deploy/sonic/005_UpgradeOriginARMSetBufferScript.s.sol @@ -10,8 +10,6 @@ import {OriginARM} from "contracts/OriginARM.sol"; import {AbstractDeployScript} from "script/deploy/helpers/AbstractDeployScript.s.sol"; contract $005_UpgradeOriginARMSetBufferScript is AbstractDeployScript("005_UpgradeOriginARMSetBufferScript") { - bool public override proposalExecuted = true; - OriginARM public originARMImpl; function _execute() internal override {