diff --git a/contracts/utils/GovFive.sol b/contracts/utils/GovFive.sol index ed191769..b7098540 100644 --- a/contracts/utils/GovFive.sol +++ b/contracts/utils/GovFive.sol @@ -7,7 +7,6 @@ import {Addresses} from "contracts/utils/Addresses.sol"; import "forge-std/console.sol"; import {TimelockController} from "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/governance/TimelockController.sol"; -import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/utils/Strings.sol"; library GovFive { struct GovFiveAction { @@ -50,8 +49,7 @@ library GovFive { GovFiveAction memory propAction = prop.actions[i]; targets[i] = propAction.receiver; - payloads[i] = - abi.encodePacked(abi.encodePacked(bytes4(keccak256(bytes(propAction.fullsig)))), propAction.data); + payloads[i] = abi.encodePacked(bytes4(keccak256(bytes(propAction.fullsig))), propAction.data); } bytes32 salt = keccak256(bytes(prop.description)); @@ -59,17 +57,19 @@ library GovFive { TimelockController timelock = TimelockController(payable(Addresses.TIMELOCK)); receiver = Addresses.TIMELOCK; - opHash = timelock.hashOperationBatch(targets, values, payloads, hex"", salt); + opHash = timelock.hashOperationBatch(targets, values, payloads, bytes32(0), salt); if (timelock.isOperation(opHash)) { bytes4 executeSig = bytes4(keccak256(bytes("executeBatch(address[],uint256[],bytes[],bytes32,bytes32)"))); - payload = abi.encodePacked(executeSig, abi.encode(targets, values, payloads, hex"", salt)); + console.log("Yet to be exeucted."); + payload = abi.encodePacked(executeSig, abi.encode(targets, values, payloads, bytes32(0), salt)); } else { bytes4 scheduleSig = - bytes4(keccak256(bytes("scheduleBatch(address[],uint256[],bytes[],bytes32,bytes32,delay)"))); + bytes4(keccak256(bytes("scheduleBatch(address[],uint256[],bytes[],bytes32,bytes32,uint256)"))); - payload = abi.encodePacked(scheduleSig, abi.encode(targets, values, payloads, hex"", salt, 2 days)); + console.log("Yet to be scheduled."); + payload = abi.encodePacked(scheduleSig, abi.encode(targets, values, payloads, bytes32(0), salt, 2 days)); } } @@ -113,6 +113,10 @@ library GovFive { console.log("Scheduling..."); (bool success, bytes memory data) = receiver.call(payload); + if (!success || !timelock.isOperation(opHash)) { + revert("Failed to schedule"); + } + (receiver, payload, opHash) = getSafeTxData(prop); } @@ -125,6 +129,12 @@ library GovFive { (bool success, bytes memory data) = receiver.call(payload); + if (!success || !timelock.isOperationDone(opHash)) { + revert("Failed to execute"); + } + + console.log("Executed"); + vm.stopPrank(); } diff --git a/contracts/utils/GovProposalHelper.sol b/contracts/utils/GovProposalHelper.sol index d7a877cd..03a2281d 100644 --- a/contracts/utils/GovProposalHelper.sol +++ b/contracts/utils/GovProposalHelper.sol @@ -5,11 +5,10 @@ pragma solidity 0.8.10; import {Addresses} from "contracts/utils/Addresses.sol"; import "forge-std/console.sol"; -import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/utils/Strings.sol"; import {IGovernor} from "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/governance/IGovernor.sol"; import {Governance} from "../Governance.sol"; -import "contracts/utils/VmHelper.sol"; +import {Vm} from "forge-std/Vm.sol"; struct GovAction { address target; @@ -24,8 +23,6 @@ struct GovProposal { } library GovProposalHelper { - using VmHelper for Vm; - function id(GovProposal memory prop) internal view returns (uint256 proposalId) { bytes32 descriptionHash = keccak256(bytes(prop.description)); (address[] memory targets, uint256[] memory values, bytes[] memory calldatas) = getParams(prop); diff --git a/contracts/utils/VmHelper.sol b/contracts/utils/VmHelper.sol deleted file mode 100644 index 0c964780..00000000 --- a/contracts/utils/VmHelper.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.10; - -import "forge-std/Vm.sol"; - -library VmHelper { - function getVM() internal view returns (Vm vm) { - address VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); - vm = Vm(VM_ADDRESS); - } - - function isForkEnv(Vm vm) public view returns (bool) { - return vm.isContext(VmSafe.ForgeContext.ScriptDryRun) || vm.isContext(VmSafe.ForgeContext.Test) - || vm.isContext(VmSafe.ForgeContext.TestGroup); - } - - function isTestEnv(Vm vm) public view returns (bool) { - return vm.isContext(VmSafe.ForgeContext.Test) || vm.isContext(VmSafe.ForgeContext.TestGroup); - } -} diff --git a/script/deploy/DeployManager.sol b/script/deploy/DeployManager.sol index aa7a7a72..710ed0f2 100644 --- a/script/deploy/DeployManager.sol +++ b/script/deploy/DeployManager.sol @@ -12,18 +12,23 @@ import {MigrationZapperScript} from "./mainnet/012_MigrationZapperScript.sol"; import {UpgradeMigratorScript} from "./mainnet/013_UpgradeMigratorScript.sol"; import {XOGNGovernanceScript} from "./mainnet/014_xOGNGovernanceScript.sol"; -import "contracts/utils/VmHelper.sol"; +import {VmSafe} from "forge-std/Vm.sol"; contract DeployManager is Script { - using VmHelper for Vm; - mapping(string => address) public deployedContracts; mapping(string => bool) public scriptsExecuted; string internal forkFileId = ""; + bool public isForked; + + constructor() { + isForked = vm.isContext(VmSafe.ForgeContext.ScriptDryRun) || vm.isContext(VmSafe.ForgeContext.TestGroup); + forkFileId = Strings.toString(block.timestamp); + } + function getDeploymentFilePath() public view returns (string memory) { - return vm.isForkEnv() ? getForkDeploymentFilePath() : getMainnetDeploymentFilePath(); + return isForked ? getForkDeploymentFilePath() : getMainnetDeploymentFilePath(); } function getMainnetDeploymentFilePath() public view returns (string memory) { @@ -34,9 +39,11 @@ contract DeployManager is Script { return string(abi.encodePacked(vm.projectRoot(), "/build/deployments-fork", forkFileId, ".json")); } - function setUp() external { - forkFileId = Strings.toString(block.timestamp); + function setForkFileId(string memory _forkFileId) external { + forkFileId = _forkFileId; + } + function setUp() external { string memory chainIdStr = Strings.toString(block.chainid); string memory chainIdKey = string(abi.encodePacked(".", chainIdStr)); @@ -54,7 +61,7 @@ contract DeployManager is Script { ); } - if (vm.isForkEnv()) { + if (isForked) { // Duplicate Mainnet File vm.writeFile(getForkDeploymentFilePath(), vm.readFile(mainnetFilePath)); } @@ -70,7 +77,11 @@ contract DeployManager is Script { } function _runDeployFile(BaseMainnetScript deployScript) internal { - if (deployScript.skip()) { + if (deployScript.proposalExecuted()) { + // No action to do + return; + } else if (deployScript.skip()) { + console.log("Skipping deployment (skip() == true)"); return; } @@ -114,9 +125,10 @@ contract DeployManager is Script { } if (scriptsExecuted[deployScript.DEPLOY_NAME()]) { + console.log("Skipping deployment (already deployed)"); + // Governance handling deployScript.handleGovernanceProposal(); - console.log("Skipping already deployed script"); } else { // Deployment deployScript.setUp(); diff --git a/script/deploy/mainnet/010_xOGNSetupScript.sol b/script/deploy/mainnet/010_xOGNSetupScript.sol index 5f159417..23b8e4a9 100644 --- a/script/deploy/mainnet/010_xOGNSetupScript.sol +++ b/script/deploy/mainnet/010_xOGNSetupScript.sol @@ -21,6 +21,7 @@ import {IMintableERC20} from "contracts/interfaces/IMintableERC20.sol"; contract XOGNSetupScript is BaseMainnetScript { string public constant override DEPLOY_NAME = "010_xOGNSetup"; + bool public constant override proposalExecuted = true; constructor() {} diff --git a/script/deploy/mainnet/011_OgnOgvMigrationScript.sol b/script/deploy/mainnet/011_OgnOgvMigrationScript.sol index e6fe8b11..5b6c71ec 100644 --- a/script/deploy/mainnet/011_OgnOgvMigrationScript.sol +++ b/script/deploy/mainnet/011_OgnOgvMigrationScript.sol @@ -20,6 +20,7 @@ contract OgnOgvMigrationScript is BaseMainnetScript { using GovProposalHelper for GovProposal; string public constant override DEPLOY_NAME = "011_OgnOgvMigration"; + bool public constant override proposalExecuted = true; GovProposal public govProposal; diff --git a/script/deploy/mainnet/012_MigrationZapperScript.sol b/script/deploy/mainnet/012_MigrationZapperScript.sol index dc5f2aca..c3891552 100644 --- a/script/deploy/mainnet/012_MigrationZapperScript.sol +++ b/script/deploy/mainnet/012_MigrationZapperScript.sol @@ -12,8 +12,6 @@ import {Governance} from "contracts/Governance.sol"; import {GovFive} from "contracts/utils/GovFive.sol"; -import {VmHelper} from "utils/VmHelper.sol"; - import {MigrationZapper} from "contracts/MigrationZapper.sol"; import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/token/ERC20/extensions/ERC20Votes.sol"; @@ -21,11 +19,11 @@ import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/governance/TimelockC contract MigrationZapperScript is BaseMainnetScript { using GovFive for GovFive.GovFiveProposal; - using VmHelper for Vm; GovFive.GovFiveProposal public govProposal; string public constant override DEPLOY_NAME = "012_MigrationZapper"; + bool public constant override proposalExecuted = true; constructor() {} diff --git a/script/deploy/mainnet/013_UpgradeMigratorScript.sol b/script/deploy/mainnet/013_UpgradeMigratorScript.sol index d2fb74bb..2bc9ac6b 100644 --- a/script/deploy/mainnet/013_UpgradeMigratorScript.sol +++ b/script/deploy/mainnet/013_UpgradeMigratorScript.sol @@ -3,30 +3,21 @@ pragma solidity 0.8.10; import "./BaseMainnetScript.sol"; -import {Vm} from "forge-std/Vm.sol"; import {Addresses} from "contracts/utils/Addresses.sol"; -import {Timelock} from "contracts/Timelock.sol"; -import {Governance} from "contracts/Governance.sol"; - import {GovFive} from "contracts/utils/GovFive.sol"; -import {VmHelper} from "utils/VmHelper.sol"; - import {Migrator} from "contracts/Migrator.sol"; import {OgvStaking} from "contracts/OgvStaking.sol"; -import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/token/ERC20/extensions/ERC20Votes.sol"; -import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/governance/TimelockController.sol"; - contract UpgradeMigratorScript is BaseMainnetScript { using GovFive for GovFive.GovFiveProposal; - using VmHelper for Vm; GovFive.GovFiveProposal public govProposal; string public constant override DEPLOY_NAME = "013_UpgradeMigrator"; + bool public constant override proposalExecuted = false; constructor() {} diff --git a/script/deploy/mainnet/014_xOGNGovernanceScript.sol b/script/deploy/mainnet/014_xOGNGovernanceScript.sol index 053b7946..263260dc 100644 --- a/script/deploy/mainnet/014_xOGNGovernanceScript.sol +++ b/script/deploy/mainnet/014_xOGNGovernanceScript.sol @@ -12,18 +12,16 @@ import {Governance} from "contracts/Governance.sol"; import {GovFive} from "contracts/utils/GovFive.sol"; -import {VmHelper} from "utils/VmHelper.sol"; - -import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/token/ERC20/extensions/ERC20Votes.sol"; -import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/governance/TimelockController.sol"; +import {ERC20Votes} from "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/token/ERC20/extensions/ERC20Votes.sol"; +import {TimelockController} from "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/governance/TimelockController.sol"; contract XOGNGovernanceScript is BaseMainnetScript { using GovFive for GovFive.GovFiveProposal; - using VmHelper for Vm; GovFive.GovFiveProposal public govProposal; string public constant override DEPLOY_NAME = "014_xOGNGovernance"; + bool public constant override proposalExecuted = false; uint256 public constant OGN_EPOCH = 1717041600; // May 30, 2024 GMT @@ -45,9 +43,6 @@ contract XOGNGovernanceScript is BaseMainnetScript { address xognGov = deployedContracts["XOGN_GOV"]; - address ognRewardsSourceProxy = deployedContracts["OGN_REWARDS_SOURCE"]; - address veOgvImpl = deployedContracts["VEOGV_IMPL"]; - govProposal.setName("Grant access to OGN Governance"); govProposal.setDescription("Grant access to OGN Governance"); @@ -88,6 +83,6 @@ contract XOGNGovernanceScript is BaseMainnetScript { function skip() external view override returns (bool) { // Don't deploy on Mainnet for now - return !vm.isForkEnv(); + return !this.isForked(); } } diff --git a/script/deploy/mainnet/BaseMainnetScript.sol b/script/deploy/mainnet/BaseMainnetScript.sol index 15fe1aad..e5d8319a 100644 --- a/script/deploy/mainnet/BaseMainnetScript.sol +++ b/script/deploy/mainnet/BaseMainnetScript.sol @@ -2,20 +2,18 @@ pragma solidity 0.8.10; -import "forge-std/Script.sol"; -import "OpenZeppelin/openzeppelin-contracts@4.6.0/contracts/utils/Strings.sol"; +import "forge-std/console.sol"; + +import {Script} from "forge-std/Script.sol"; +import {Vm, VmSafe} from "forge-std/Vm.sol"; import {Addresses} from "contracts/utils/Addresses.sol"; import {GovProposal, GovProposalHelper} from "contracts/utils/GovProposalHelper.sol"; -import "utils/VmHelper.sol"; - abstract contract BaseMainnetScript is Script { - using VmHelper for Vm; using GovProposalHelper for GovProposal; uint256 public deployBlockNum = type(uint256).max; - bool isForked = false; // DeployerRecord stuff to be extracted as well struct DeployRecord { @@ -42,6 +40,10 @@ abstract contract BaseMainnetScript is Script { deployedContracts[name] = addr; } + function isForked() public view returns (bool) { + return vm.isContext(VmSafe.ForgeContext.ScriptDryRun) || vm.isContext(VmSafe.ForgeContext.TestGroup); + } + function setUp() external {} function run() external { @@ -54,9 +56,7 @@ abstract contract BaseMainnetScript is Script { return; } - isForked = vm.isForkEnv(); - - if (isForked) { + if (this.isForked()) { address impersonator = Addresses.INITIAL_DEPLOYER; console.log("Running script on mainnet fork impersonating: %s", impersonator); vm.startPrank(impersonator); @@ -69,7 +69,7 @@ abstract contract BaseMainnetScript is Script { _execute(); - if (isForked) { + if (this.isForked()) { vm.stopPrank(); _buildGovernanceProposal(); _fork(); @@ -80,6 +80,8 @@ abstract contract BaseMainnetScript is Script { function DEPLOY_NAME() external view virtual returns (string memory); + function proposalExecuted() external view virtual returns (bool); + function skip() external view virtual returns (bool) { return false; } @@ -91,6 +93,10 @@ abstract contract BaseMainnetScript is Script { function _buildGovernanceProposal() internal virtual {} function handleGovernanceProposal() external virtual { + if (this.proposalExecuted()) { + return; + } + _buildGovernanceProposal(); _fork(); } diff --git a/tests/staking/MigratorForkTest.t.sol b/tests/staking/MigratorForkTest.t.sol index d6578682..f7f863c3 100644 --- a/tests/staking/MigratorForkTest.t.sol +++ b/tests/staking/MigratorForkTest.t.sol @@ -23,11 +23,13 @@ contract MigratorForkTest is Test { IMintableERC20 public ogn; uint256 constant OGN_EPOCH = 1717041600; // May 30, 2024 GMT - address public ogvWhale = 0x70fCE97d671E81080CA3ab4cc7A59aAc2E117137; + address public ogvWhale = 0xD066c92d5dD4fD19E7F053Cf63EBB01Aaaa233CE; constructor() { deployManager = new DeployManager(); + deployManager.setForkFileId(string(abi.encodePacked(vm.toString(block.chainid), "-MigratorForkTest"))); + deployManager.setUp(); deployManager.run(); } @@ -46,6 +48,10 @@ contract MigratorForkTest is Test { ogv.approve(address(veogv), type(uint256).max); vm.stopPrank(); + vm.startPrank(Addresses.TIMELOCK); + ogn.mint(ogvWhale, 10_000_000 ether); // Mint some OGV for the whale + vm.stopPrank(); + vm.warp(OGN_EPOCH + 100 days); if (veogv.balanceOf(ogvWhale) == 0) { diff --git a/tests/staking/OGNRewardsSourceForkTest.t.sol b/tests/staking/OGNRewardsSourceForkTest.t.sol index 53a62313..20c1afc5 100644 --- a/tests/staking/OGNRewardsSourceForkTest.t.sol +++ b/tests/staking/OGNRewardsSourceForkTest.t.sol @@ -34,6 +34,8 @@ contract OGNRewardsSourceForkTest is Test { constructor() { deployManager = new DeployManager(); + deployManager.setForkFileId(string(abi.encodePacked(vm.toString(block.chainid), "-OGNRewardsSourceForkTest"))); + deployManager.setUp(); deployManager.run(); } diff --git a/tests/staking/XOGNStakingForkTest.t..sol b/tests/staking/XOGNStakingForkTest.t..sol index 4342e850..b4b6b4df 100644 --- a/tests/staking/XOGNStakingForkTest.t..sol +++ b/tests/staking/XOGNStakingForkTest.t..sol @@ -35,6 +35,8 @@ contract XOGNStakingForkTest is Test { constructor() { deployManager = new DeployManager(); + deployManager.setForkFileId(string(abi.encodePacked(vm.toString(block.chainid), "-XOGNStakingForkTest"))); + deployManager.setUp(); deployManager.run(); } diff --git a/tests/staking/ZapperForkTest.t.sol b/tests/staking/ZapperForkTest.t.sol index 51f6b799..83674fdd 100644 --- a/tests/staking/ZapperForkTest.t.sol +++ b/tests/staking/ZapperForkTest.t.sol @@ -26,11 +26,13 @@ contract ZapperForkTest is Test { IMintableERC20 public ogv; IMintableERC20 public ogn; - address public ogvWhale = 0x70fCE97d671E81080CA3ab4cc7A59aAc2E117137; + address public ogvWhale = 0x12D7EF3C933D091210cD931224Ead45D9cFdDdE0; constructor() { deployManager = new DeployManager(); + deployManager.setForkFileId(string(abi.encodePacked(vm.toString(block.chainid), "-ZapperForkTest"))); + deployManager.setUp(); deployManager.run(); } @@ -51,6 +53,10 @@ contract ZapperForkTest is Test { ogv.approve(address(veogv), type(uint256).max); vm.stopPrank(); + vm.startPrank(Addresses.TIMELOCK); + ogn.mint(ogvWhale, 10_000_000 ether); // Mint some OGV for the whale + vm.stopPrank(); + vm.warp(OGN_EPOCH + 100 days); if (veogv.balanceOf(ogvWhale) == 0) {