diff --git a/contracts/AngleGovernor.sol b/contracts/AngleGovernor.sol index 8953a6b..bfc9959 100644 --- a/contracts/AngleGovernor.sol +++ b/contracts/AngleGovernor.sol @@ -8,10 +8,8 @@ import { Governor } from "oz/governance/Governor.sol"; import { GovernorPreventLateQuorum } from "oz/governance/extensions/GovernorPreventLateQuorum.sol"; import { GovernorVotesQuorumFraction, GovernorVotes } from "oz/governance/extensions/GovernorVotesQuorumFraction.sol"; import { GovernorSettings } from "oz/governance/extensions/GovernorSettings.sol"; -import { TimelockController } from "oz/governance/TimelockController.sol"; import { IERC5805 } from "oz/interfaces/IERC5805.sol"; -import { GovernorToken } from "./external/GovernorToken.sol"; import { GovernorCountingFractional } from "./external/GovernorCountingFractional.sol"; import { GovernorShortCircuit } from "./external/GovernorShortCircuit.sol"; @@ -20,15 +18,14 @@ import "./utils/Errors.sol"; /// @title AngleGovernor /// @author Angle Labs, Inc /// @dev Core of Angle governance system, extending various OpenZeppelin modules -/// @dev This contract overrides some OpenZeppelin function, like those in `GovernorSettings` to introduce -/// the `onlyExecutor` modifier which ensures that only the Timelock contract can update the system's parameters +/// @dev This contract overrides some OpenZeppelin functions, like those in `GovernorSettings` to introduce +/// the `onlyGovernance` modifier which ensures that only the Timelock contract can update the system's parameters /// @dev The time parameters (`votingDelay`, `votingPeriod`, ...) are expressed here in timestamp units, but the -/// also has a `votingDelayBlocks` parameters which must be set in accordance to the `votingDelay` -/// @dev The `state` and `propose` functions here were forked from FRAX governance implementation +/// contract also has a `votingDelayBlocks` parameter which must be set in accordance to the `votingDelay` that is +/// used when computing quorums and whether proposals can be shortcircuited /// @custom:security-contact contact@angle.money contract AngleGovernor is GovernorSettings, - GovernorToken, GovernorPreventLateQuorum, GovernorCountingFractional, GovernorVotesQuorumFraction, @@ -38,24 +35,16 @@ contract AngleGovernor is EVENTS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ - event TimelockChange(address oldTimelock, address newTimelock); + event TimelockChange(address indexed oldTimelock, address indexed newTimelock); /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// VARIABLES //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ /// @notice Timelock address that owns this contract and can change the system's parameters - TimelockController public timelock; - - /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - MODIFIER - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ - - /// @notice Checks whether the sender is the system's executor - modifier onlyExecutor() { - if (msg.sender != _executor()) revert NotExecutor(); - _; - } + address public timelock; + /// @notice Address where veANGLE holders can delegate their vote + IERC5805 public veANGLEVotingDelegation; /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTOR @@ -63,7 +52,7 @@ contract AngleGovernor is constructor( IVotes _token, - TimelockController timelockAddress, + address timelockAddress, uint48 initialVotingDelay, uint32 initialVotingPeriod, uint256 initialProposalThreshold, @@ -73,7 +62,6 @@ contract AngleGovernor is uint256 initialVotingDelayBlocks ) Governor("AngleGovernor") - GovernorToken(_token) GovernorSettings(initialVotingDelay, initialVotingPeriod, initialProposalThreshold) GovernorPreventLateQuorum(initialVoteExtension) GovernorVotes(_token) @@ -81,84 +69,29 @@ contract AngleGovernor is GovernorShortCircuit(initialShortCircuitNumerator, initialVotingDelayBlocks) { _updateTimelock(timelockAddress); + veANGLEVotingDelegation = IERC5805(address(_token)); } /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - VIEW FUNCTIONS - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ - - function _executor() internal view override(Governor) returns (address) { - return address(timelock); - } - - /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - SETTERS - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ - - /// @notice Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, - /// so updates must be proposed, scheduled, and executed through governance proposals. - /// @dev It is not recommended to change the timelock while there are other queued governance proposals. - function updateTimelock(TimelockController newTimelock) external virtual onlyExecutor { - _updateTimelock(newTimelock); - } - - /// @inheritdoc GovernorSettings - function setVotingDelay(uint48 newVotingDelay) public override onlyExecutor { - _setVotingDelay(newVotingDelay); - } - - /// @inheritdoc GovernorSettings - function setVotingPeriod(uint32 newVotingPeriod) public override onlyExecutor { - _setVotingPeriod(newVotingPeriod); - } - - /// @inheritdoc GovernorSettings - function setProposalThreshold(uint256 newProposalThreshold) public override onlyExecutor { - _setProposalThreshold(newProposalThreshold); - } - - /// @param veANGLEVotingDelegation New IERC5805 veANGLEVotingDelegation contract address - function setVeANGLEVotingDelegation(address veANGLEVotingDelegation) external onlyExecutor { - _setVeANGLEVotingDelegation(veANGLEVotingDelegation); - } - - /// @inheritdoc GovernorVotesQuorumFraction - function updateQuorumNumerator(uint256 newQuorumNumerator) external override onlyExecutor { - _updateQuorumNumerator(newQuorumNumerator); - } - - /// @param newShortCircuitNumerator Number expressed as x/100 (percentage) - function updateShortCircuitNumerator(uint256 newShortCircuitNumerator) external onlyExecutor { - _updateShortCircuitNumerator(newShortCircuitNumerator); - } - - /// @notice Changes the amount of blocks before the voting snapshot - function setVotingDelayBlocks(uint256 newVotingDelayBlocks) external onlyExecutor { - _setVotingDelayBlocks(newVotingDelayBlocks); - } - - /// @inheritdoc GovernorPreventLateQuorum - function setLateQuorumVoteExtension( - uint48 newVoteExtension - ) public override(GovernorPreventLateQuorum) onlyExecutor { - _setLateQuorumVoteExtension(newVoteExtension); - } - - /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - OVERRIDES + EXTERNAL OVERRIDES //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc Governor // solhint-disable-next-line - /// @notice Fork from Frax Finance: https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/FraxGovernorAlpha.sol - function state(uint256 proposalId) public view override returns (ProposalState) { - ProposalState classicProposalState = Governor.state(proposalId); - + /// @notice Base implementation taken from Frax Finance: https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/FraxGovernorAlpha.sol + /// @dev In this governor implementation, the owner of the contract is a Timelock contract. Yet not all proposals + /// have to go through the Timelock contract, and so proposals may appear as executed when in fact they are + /// queued in a timelock + function state(uint256 proposalId) public view override(Governor) returns (ProposalState) { + ProposalState currentState = super.state(proposalId); if ( - classicProposalState == ProposalState.Executed || - classicProposalState == ProposalState.Canceled || - classicProposalState == ProposalState.Pending - ) return classicProposalState; + currentState == ProposalState.Executed || + currentState == ProposalState.Canceled || + currentState == ProposalState.Pending + ) return currentState; + + uint256 snapshot = proposalSnapshot(proposalId); + if ($snapshotTimestampToSnapshotBlockNumber[snapshot] >= block.number) return ProposalState.Pending; // Allow early execution when overwhelming majority (bool isShortCircuitFor, bool isShortCircuitAgainst) = _shortCircuit(proposalId); @@ -166,7 +99,7 @@ contract AngleGovernor is return ProposalState.Succeeded; } else if (isShortCircuitAgainst) { return ProposalState.Defeated; - } else return classicProposalState; + } else return currentState; } /// @inheritdoc GovernorVotesQuorumFraction @@ -189,39 +122,40 @@ contract AngleGovernor is } /// @inheritdoc GovernorSettings - function votingDelay() public view override(Governor, GovernorSettings) returns (uint256) { - return GovernorSettings.votingDelay(); + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return GovernorSettings.proposalThreshold(); } - /// @inheritdoc GovernorSettings - function votingPeriod() public view override(Governor, GovernorSettings) returns (uint256) { - return GovernorSettings.votingPeriod(); + /// @inheritdoc GovernorVotes + function token() public view override(GovernorVotes) returns (IERC5805) { + return veANGLEVotingDelegation; } - /// @inheritdoc GovernorSettings - function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { - return GovernorSettings.proposalThreshold(); + /// @inheritdoc GovernorVotes + // solhint-disable-next-line + function CLOCK_MODE() public pure override(GovernorVotes, Governor) returns (string memory) { + return "mode=timestamp"; } /// @inheritdoc GovernorVotes - function token() public view override(GovernorToken, GovernorVotes) returns (IERC5805) { - return GovernorToken.token(); + function clock() public view override(GovernorVotes, Governor) returns (uint48) { + return uint48(block.timestamp); } /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - INTERNALS + INTERNAL OVERRIDES //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc Governor // solhint-disable-next-line - /// @notice Fork from Frax Finance: https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/FraxGovernorAlpha.sol + /// @notice Base implementation taken from Frax Finance: https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/FraxGovernorAlpha.sol function _propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description, address proposer - ) internal override returns (uint256 proposalId) { + ) internal override(Governor) returns (uint256 proposalId) { proposalId = super._propose(targets, values, calldatas, description, proposer); // cf Frax Finance contracts @@ -244,8 +178,30 @@ contract AngleGovernor is return GovernorPreventLateQuorum._castVote(proposalId, account, support, reason, params); } - function _updateTimelock(TimelockController newTimelock) private { - emit TimelockChange(address(timelock), address(newTimelock)); + /// @inheritdoc Governor + function _executor() internal view override(Governor) returns (address) { + return address(timelock); + } + + /// @inheritdoc Governor + function _checkGovernance() internal view override(Governor) { + if (msg.sender != _executor()) revert NotExecutor(); + } + + /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + SETTER + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ + + /// @notice Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, + /// so updates must be proposed, scheduled, and executed through governance proposals. + /// @dev It is not recommended to change the timelock while there are other queued governance proposals. + function updateTimelock(address newTimelock) external virtual onlyGovernance { + _updateTimelock(newTimelock); + } + + function _updateTimelock(address newTimelock) internal { + if (newTimelock == address(0)) revert ZeroAddress(); + emit TimelockChange(timelock, newTimelock); timelock = newTimelock; } } diff --git a/contracts/VeANGLEVotingDelegation.sol b/contracts/VeANGLEVotingDelegation.sol index 2df7792..9213384 100644 --- a/contracts/VeANGLEVotingDelegation.sol +++ b/contracts/VeANGLEVotingDelegation.sol @@ -13,7 +13,7 @@ import { IveANGLEVotingDelegation } from "./interfaces/IveANGLEVotingDelegation. /// @notice Contract that keeps track of voting weights and delegations, leveraging veANGLE /// @author Jon Walch (Frax Finance) https://github.com/jonwalch // solhint-disable-next-line -/// @dev Fork from Frax Finance: https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/veANGLEVotingDelegation.sol +/// @dev Fork from Frax Finance: https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/VeFxsVotingDelegation.sol /// @dev The Fxs in the variable names and comments have been replaced by ANGLE contract VeANGLEVotingDelegation is EIP712, IERC5805 { using SafeCast for uint256; @@ -24,8 +24,7 @@ contract VeANGLEVotingDelegation is EIP712, IERC5805 { /// @notice Max veANGLE lock duration uint256 public constant MAX_LOCK_DURATION = 365 days * 4; - /// @notice vote weight multiplier taken from veANGLE - /// TODO: update to our case + /// @notice Vote weight multiplier taken from veANGLE uint256 public constant VOTE_WEIGHT_MULTIPLIER = 1; /// @notice Typehash needed for delegations by signature @@ -49,7 +48,7 @@ contract VeANGLEVotingDelegation is EIP712, IERC5805 { mapping(address delegate => mapping(uint256 week => IveANGLEVotingDelegation.Expiration)) public $expiredDelegations; - /// @notice The ```constructor``` function is called on deployment + /// @notice Constructor of the contract, called on deployment /// @param veANGLE Address of veANGLE contract constructor(address veANGLE, string memory name, string memory version) EIP712(name, version) { VE_ANGLE = IveANGLE(veANGLE); diff --git a/contracts/external/GovernorCountingFractional.sol b/contracts/external/GovernorCountingFractional.sol index af68dec..c03fbbc 100644 --- a/contracts/external/GovernorCountingFractional.sol +++ b/contracts/external/GovernorCountingFractional.sol @@ -8,18 +8,14 @@ import { SafeCast } from "oz/utils/math/SafeCast.sol"; import "../utils/Errors.sol"; -/** - * @notice Extension of {Governor} for 3 option fractional vote counting. When - * voting, a delegate may split their vote weight between Against/For/Abstain. - * This is most useful when the delegate is itself a contract, implementing its - * own rules for voting. By allowing a contract-delegate to split its vote - * weight, the voting preferences of many disparate token holders can be rolled - * up into a single vote to the Governor itself. Some example use cases include - * voting with tokens that are held by a DeFi pool, voting from L2 with tokens - * held by a bridge, or voting privately from a shielded pool using zero - * knowledge proofs. - * @author ScopeLift - */ +/// @title GovernorCountingFractional +/// @notice Extension of {Governor} for 3 option fractional vote counting. When voting, a delegate may split their +/// vote weight between Against/For/Abstain. This is most useful when the delegate is itself a contract, implementing +/// its own rules for voting. By allowing a contract-delegate to split its vote weight, the voting preferences of many +/// disparate token holders can be rolled up into a single vote to the Governor itself. Some example use cases include +/// voting with tokens that are held by a DeFi pool, voting from L2 with tokens held by a bridge, or voting privately +/// from a shielded pool using zero knowledge proofs. +/// @author ScopeLift //solhint-disable-next-line // Fork from: https://github.com/ScopeLift/flexible-voting/blob/4399694c1a70d9e236c4c072802bfbe8e4951bf0/src/GovernorCountingFractional.sol abstract contract GovernorCountingFractional is Governor { diff --git a/contracts/external/GovernorShortCircuit.sol b/contracts/external/GovernorShortCircuit.sol index edeadad..021e1fa 100644 --- a/contracts/external/GovernorShortCircuit.sol +++ b/contracts/external/GovernorShortCircuit.sol @@ -12,10 +12,10 @@ import "../utils/Errors.sol"; /// @title GovernorShortCircuit /// @notice Extends governor to pass propositions if the quorum is reached before the end of the voting period -/// @author Angle Labs, Inc /// @author Jon Walch (Frax Finance) https://github.com/jonwalch //solhint-disable-next-line -/// @notice https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/veANGLEVotingDelegation.sol +/// @notice Taken from: +/// https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/FraxGovernorBase.sol abstract contract GovernorShortCircuit is GovernorVotes, GovernorCountingFractional, GovernorVotesQuorumFraction { using SafeCast for *; using Checkpoints for Checkpoints.Trace224; @@ -101,6 +101,20 @@ abstract contract GovernorShortCircuit is GovernorVotes, GovernorCountingFractio quorumDenominator(); } + /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + SETTERS + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ + + /// @param newShortCircuitNumerator Number expressed as x/100 (percentage) + function updateShortCircuitNumerator(uint256 newShortCircuitNumerator) external onlyGovernance { + _updateShortCircuitNumerator(newShortCircuitNumerator); + } + + /// @notice Changes the amount of blocks before the voting snapshot + function setVotingDelayBlocks(uint256 newVotingDelayBlocks) external onlyGovernance { + _setVotingDelayBlocks(newVotingDelayBlocks); + } + /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// INTERNALS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ diff --git a/contracts/external/GovernorToken.sol b/contracts/external/GovernorToken.sol deleted file mode 100644 index 62c19ae..0000000 --- a/contracts/external/GovernorToken.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.20; - -import { IVotes } from "oz/governance/utils/IVotes.sol"; -import { GovernorVotes, IERC5805 } from "oz/governance/extensions/GovernorVotes.sol"; - -/** - * @notice Extension of {Governor} with `internal` and not `private` _token - */ -abstract contract GovernorToken is GovernorVotes { - event VeANGLEVotingDelegationSet(address oldVotingDelegation, address newVotingDelegation); - - IERC5805 internal _token_; - - constructor(IVotes _token) { - _setVeANGLEVotingDelegation(address(_token)); - } - - /// @inheritdoc GovernorVotes - function token() public view virtual override returns (IERC5805) { - return _token_; - } - - /// @param veANGLEVotingDelegation New IERC5805 VeANGLEVotingDelegation contract address - function _setVeANGLEVotingDelegation(address veANGLEVotingDelegation) internal { - address oldVeANGLEVotingDelegation = address(token()); - _token_ = IERC5805(veANGLEVotingDelegation); - emit VeANGLEVotingDelegationSet({ - oldVotingDelegation: oldVeANGLEVotingDelegation, - newVotingDelegation: veANGLEVotingDelegation - }); - } -} diff --git a/contracts/utils/Errors.sol b/contracts/utils/Errors.sol index 205ad7b..e8ac235 100644 --- a/contracts/utils/Errors.sol +++ b/contracts/utils/Errors.sol @@ -16,3 +16,4 @@ error OmnichainProposalSenderInvalidEndpoint(); error OmnichainProposalSenderInvalidExecParams(); error OmnichainProposalSenderNoStoredPayload(); error ShortCircuitNumeratorGreaterThanQuorumDenominator(); +error ZeroAddress(); diff --git a/package.json b/package.json index 35ffbfa..e13efea 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "test:unit": "forge test -vvv --gas-report --match-path \"test/unit/**/*.sol\"", "test:invariant": "forge test -vvv --gas-report --match-path \"test/invariant/**/*.sol\"", "test:fuzz": "forge test -vvv --gas-report --match-path \"test/fuzz/**/*.sol\"", - "test": "FOUNDRY_PROFILE=dev forge test -vvv", + "test": "FOUNDRY_PROFILE=dev forge test -vvvv", "slither": "slither .", "lcov:clean": "lcov --remove lcov.info -o lcov.info 'test/**' 'scripts/**' 'contracts/transmuter/configs/**' 'contracts/utils/**'", "lcov:generate-html": "genhtml lcov.info --output=coverage", @@ -41,4 +41,4 @@ "solhint-plugin-prettier": "^0.0.5" }, "dependencies": {} -} \ No newline at end of file +} diff --git a/test/fuzz/GovernorCountingFractional.t.sol b/test/fuzz/GovernorCountingFractional.t.sol index 506e9a7..f4ff07b 100644 --- a/test/fuzz/GovernorCountingFractional.t.sol +++ b/test/fuzz/GovernorCountingFractional.t.sol @@ -8,6 +8,7 @@ import { SafeCast } from "oz/utils/math/SafeCast.sol"; import { Strings } from "oz/utils/Strings.sol"; import { MessageHashUtils } from "oz/utils/cryptography/MessageHashUtils.sol"; import { GovernorCountingSimple } from "oz/governance/extensions/GovernorCountingSimple.sol"; +import { GovernorVotesQuorumFraction } from "oz/governance/extensions/GovernorVotesQuorumFraction.sol"; import { Test, stdError } from "forge-std/Test.sol"; import { Vm } from "forge-std/Vm.sol"; @@ -112,7 +113,7 @@ contract GovernorCountingFractionalTest is Test { mainnetTimelock = new TimelockController(1 days, proposers, executors, address(this)); governor = new AngleGovernor( token, - mainnetTimelock, + address(mainnetTimelock), initialVotingDelay, initialVotingPeriod, initialProposalThreshold, @@ -180,7 +181,7 @@ contract GovernorCountingFractionalTest is Test { bytes[] memory calldatas = new bytes[](1); targets[0] = address(governor); values[0] = 0; // no ETH will be sent - calldatas[0] = abi.encodeWithSelector(AngleGovernor.updateQuorumNumerator.selector, 11); + calldatas[0] = abi.encodeWithSelector(GovernorVotesQuorumFraction.updateQuorumNumerator.selector, 11); string memory description = "A modest proposal"; uint256 proposalId = governor.hashProposal(targets, values, calldatas, keccak256(bytes(description))); diff --git a/test/unit/AngleGovernor.t.sol b/test/unit/AngleGovernor.t.sol index bb0669c..be84457 100644 --- a/test/unit/AngleGovernor.t.sol +++ b/test/unit/AngleGovernor.t.sol @@ -50,7 +50,7 @@ contract AngleGovernorTest is Test, Utils { mainnetTimelock = new TimelockController(1 days, proposers, executors, address(this)); angleGovernor = new AngleGovernor( veANGLEDelegation, - mainnetTimelock, + address(mainnetTimelock), initialVotingDelay, initialVotingPeriod, initialProposalThreshold, @@ -88,7 +88,7 @@ contract AngleGovernorTest is Test, Utils { vm.startPrank(alice); TimelockController mainnetTimelock2 = new TimelockController(1 days, proposers, executors, address(this)); vm.expectRevert(Errors.NotExecutor.selector); - angleGovernor.updateTimelock(mainnetTimelock2); + angleGovernor.updateTimelock(address(mainnetTimelock2)); vm.expectRevert(Errors.NotExecutor.selector); angleGovernor.setVotingDelay(10); vm.expectRevert(Errors.NotExecutor.selector); @@ -98,8 +98,6 @@ contract AngleGovernorTest is Test, Utils { vm.expectRevert(Errors.NotExecutor.selector); angleGovernor.setProposalThreshold(10); vm.expectRevert(Errors.NotExecutor.selector); - angleGovernor.setVeANGLEVotingDelegation(address(veANGLE)); - vm.expectRevert(Errors.NotExecutor.selector); angleGovernor.updateShortCircuitNumerator(12); vm.expectRevert(Errors.NotExecutor.selector); angleGovernor.setLateQuorumVoteExtension(12); @@ -115,10 +113,12 @@ contract AngleGovernorTest is Test, Utils { executors[0] = address(0); // Means everyone can execute TimelockController mainnetTimelock2 = new TimelockController(1 days, proposers, executors, address(this)); - vm.expectEmit(true, true, true, true, address(angleGovernor)); - emit TimelockChange(address(mainnetTimelock), address(mainnetTimelock2)); + vm.expectRevert(Errors.ZeroAddress.selector); + hoax(address(mainnetTimelock)); + angleGovernor.updateTimelock(address(0)); + hoax(address(mainnetTimelock)); - angleGovernor.updateTimelock(mainnetTimelock2); + angleGovernor.updateTimelock(address(mainnetTimelock2)); assertEq(address(angleGovernor.timelock()), address(mainnetTimelock2)); } @@ -154,15 +154,6 @@ contract AngleGovernorTest is Test, Utils { assertEq(angleGovernor.proposalThreshold(), 13); } - function test_SetVeANGLEVotingDelegation() public { - IVotes veANGLEDelegation2 = new VeANGLEVotingDelegation(address(veANGLE), "veANGLE Delegation2", "2"); - vm.expectEmit(true, true, true, true, address(angleGovernor)); - emit VeANGLEVotingDelegationSet(address(veANGLEDelegation), address(veANGLEDelegation2)); - hoax(address(mainnetTimelock)); - angleGovernor.setVeANGLEVotingDelegation(address(veANGLEDelegation2)); - assertEq(address(angleGovernor.token()), address(veANGLEDelegation2)); - } - function test_UpdateQuorumNumerator() public { vm.expectEmit(true, true, true, true, address(angleGovernor)); emit QuorumNumeratorUpdated(initialQuorumNumerator, 13); diff --git a/test/unit/GovernorStateAndPropose.t.sol b/test/unit/GovernorStateAndPropose.t.sol index f7106f1..b28c906 100644 --- a/test/unit/GovernorStateAndPropose.t.sol +++ b/test/unit/GovernorStateAndPropose.t.sol @@ -46,7 +46,7 @@ contract GovernorStateAndProposeTest is Test, Utils { mainnetTimelock = new TimelockController(1 days, proposers, executors, address(this)); angleGovernor = new AngleGovernor( veANGLEDelegation, - mainnetTimelock, + address(mainnetTimelock), initialVotingDelay, initialVotingPeriod, initialProposalThreshold, diff --git a/test/unit/SimulationSetup.t.sol b/test/unit/SimulationSetup.t.sol index 7286b8a..b72f0c1 100644 --- a/test/unit/SimulationSetup.t.sol +++ b/test/unit/SimulationSetup.t.sol @@ -70,7 +70,7 @@ contract SimulationSetup is Test { _timelocks[chainIds[i]] = new TimelockController(1 days, proposers, executors, address(this)); _governor = new AngleGovernor( veANGLEDelegation, - _timelocks[chainIds[i]], + address(_timelocks[chainIds[i]]), initialVotingDelay, initialVotingPeriod, initialProposalThreshold,