diff --git a/contracts/EmergencyProtectedTimelock.sol b/contracts/EmergencyProtectedTimelock.sol index 8ef807b1..7dc7bad7 100644 --- a/contracts/EmergencyProtectedTimelock.sol +++ b/contracts/EmergencyProtectedTimelock.sol @@ -109,7 +109,7 @@ contract EmergencyProtectedTimelock is ITimelock { _timelockState.setGovernance(newGovernance); } - function setDelays(Duration afterSubmitDelay, Duration afterScheduleDelay) external { + function setupDelays(Duration afterSubmitDelay, Duration afterScheduleDelay) external { _checkCallerIsAdminExecutor(); _timelockState.setAfterSubmitDelay(afterSubmitDelay, MAX_AFTER_SUBMIT_DELAY); _timelockState.setAfterScheduleDelay(afterScheduleDelay, MAX_AFTER_SCHEDULE_DELAY); @@ -128,22 +128,41 @@ contract EmergencyProtectedTimelock is ITimelock { // Emergency Protection Functionality // --- - function setupEmergencyProtection( - address emergencyGovernance, - address emergencyActivationCommittee, - address emergencyExecutionCommittee, - Timestamp emergencyProtectionEndDate, - Duration emergencyModeDuration - ) external { + /// @dev Sets the emergency activation committee address. + /// @param emergencyActivationCommittee The address of the emergency activation committee. + function setEmergencyProtectionActivationCommittee(address emergencyActivationCommittee) external { _checkCallerIsAdminExecutor(); - - _emergencyProtection.setEmergencyGovernance(emergencyGovernance); _emergencyProtection.setEmergencyActivationCommittee(emergencyActivationCommittee); + } + + /// @dev Sets the emergency execution committee address. + /// @param emergencyExecutionCommittee The address of the emergency execution committee. + function setEmergencyProtectionExecutionCommittee(address emergencyExecutionCommittee) external { + _checkCallerIsAdminExecutor(); + _emergencyProtection.setEmergencyExecutionCommittee(emergencyExecutionCommittee); + } + + /// @dev Sets the emergency protection end date. + /// @param emergencyProtectionEndDate The timestamp of the emergency protection end date. + function setEmergencyProtectionEndDate(Timestamp emergencyProtectionEndDate) external { + _checkCallerIsAdminExecutor(); _emergencyProtection.setEmergencyProtectionEndDate( emergencyProtectionEndDate, MAX_EMERGENCY_PROTECTION_DURATION ); + } + + /// @dev Sets the emergency mode duration. + /// @param emergencyModeDuration The duration of the emergency mode. + function setEmergencyModeDuration(Duration emergencyModeDuration) external { + _checkCallerIsAdminExecutor(); _emergencyProtection.setEmergencyModeDuration(emergencyModeDuration, MAX_EMERGENCY_MODE_DURATION); - _emergencyProtection.setEmergencyExecutionCommittee(emergencyExecutionCommittee); + } + + /// @dev Sets the emergency governance address. + /// @param emergencyGovernance The address of the emergency governance. + function setEmergencyGovernance(address emergencyGovernance) external { + _checkCallerIsAdminExecutor(); + _emergencyProtection.setEmergencyGovernance(emergencyGovernance); } /// @dev Activates the emergency mode. diff --git a/contracts/committees/HashConsensus.sol b/contracts/committees/HashConsensus.sol index 31825a1b..57387243 100644 --- a/contracts/committees/HashConsensus.sol +++ b/contracts/committees/HashConsensus.sol @@ -23,6 +23,7 @@ abstract contract HashConsensus is Ownable { error HashAlreadyUsed(bytes32 hash); error QuorumIsNotReached(); error InvalidQuorum(); + error InvalidTimelockDuration(uint256 timelock); error TimelockNotPassed(); struct HashState { @@ -155,6 +156,9 @@ abstract contract HashConsensus is Ownable { /// @param timelock The new timelock duration in seconds function setTimelockDuration(uint256 timelock) public { _checkOwner(); + if (timelock == timelockDuration) { + revert InvalidTimelockDuration(timelock); + } timelockDuration = timelock; emit TimelockDurationSet(timelock); } @@ -171,7 +175,7 @@ abstract contract HashConsensus is Ownable { /// @dev The quorum value must be greater than zero and not exceed the current number of members. /// @param executionQuorum The new quorum value to be set. function _setQuorum(uint256 executionQuorum) internal { - if (executionQuorum == 0 || executionQuorum > _members.length()) { + if (executionQuorum == 0 || executionQuorum > _members.length() || executionQuorum == quorum) { revert InvalidQuorum(); } quorum = executionQuorum; diff --git a/contracts/libraries/EmergencyProtection.sol b/contracts/libraries/EmergencyProtection.sol index 4adc7bcd..582d3fb7 100644 --- a/contracts/libraries/EmergencyProtection.sol +++ b/contracts/libraries/EmergencyProtection.sol @@ -11,6 +11,9 @@ library EmergencyProtection { error CallerIsNotEmergencyActivationCommittee(address caller); error CallerIsNotEmergencyExecutionCommittee(address caller); error EmergencyProtectionExpired(Timestamp protectedTill); + error InvalidEmergencyGovernance(address governance); + error InvalidEmergencyActivationCommittee(address committee); + error InvalidEmergencyExecutionCommittee(address committee); error InvalidEmergencyModeDuration(Duration value); error InvalidEmergencyProtectionEndDate(Timestamp value); error UnexpectedEmergencyModeState(bool value); @@ -52,7 +55,6 @@ library EmergencyProtection { } self.emergencyModeEndsAfter = self.emergencyModeDuration.addTo(now_); - emit EmergencyModeActivated(); } @@ -71,57 +73,73 @@ library EmergencyProtection { // Setup functionality // --- + /// @dev Sets the emergency governance address. + /// @param self The storage reference to the Context struct. + /// @param newEmergencyGovernance The new emergency governance address. function setEmergencyGovernance(Context storage self, address newEmergencyGovernance) internal { if (newEmergencyGovernance == self.emergencyGovernance) { - return; + revert InvalidEmergencyGovernance(newEmergencyGovernance); } self.emergencyGovernance = newEmergencyGovernance; emit EmergencyGovernanceSet(newEmergencyGovernance); } + /// @dev Sets the emergency protection end date. + /// @param self The storage reference to the Context struct. + /// @param newEmergencyProtectionEndDate The new emergency protection end date. + /// @param maxEmergencyProtectionDuration The maximum duration for the emergency protection. function setEmergencyProtectionEndDate( Context storage self, Timestamp newEmergencyProtectionEndDate, Duration maxEmergencyProtectionDuration ) internal { - if (newEmergencyProtectionEndDate > maxEmergencyProtectionDuration.addTo(Timestamps.now())) { + if ( + newEmergencyProtectionEndDate > maxEmergencyProtectionDuration.addTo(Timestamps.now()) + || newEmergencyProtectionEndDate == self.emergencyProtectionEndsAfter + ) { revert InvalidEmergencyProtectionEndDate(newEmergencyProtectionEndDate); } - - if (newEmergencyProtectionEndDate == self.emergencyProtectionEndsAfter) { - return; - } self.emergencyProtectionEndsAfter = newEmergencyProtectionEndDate; emit EmergencyProtectionEndDateSet(newEmergencyProtectionEndDate); } + /// @dev Sets the emergency mode duration. + /// @param self The storage reference to the Context struct. + /// @param newEmergencyModeDuration The new emergency mode duration. + /// @param maxEmergencyModeDuration The maximum duration for the emergency mode. function setEmergencyModeDuration( Context storage self, Duration newEmergencyModeDuration, Duration maxEmergencyModeDuration ) internal { - if (newEmergencyModeDuration > maxEmergencyModeDuration) { + if ( + newEmergencyModeDuration > maxEmergencyModeDuration + || newEmergencyModeDuration == self.emergencyModeDuration + ) { revert InvalidEmergencyModeDuration(newEmergencyModeDuration); } - if (newEmergencyModeDuration == self.emergencyModeDuration) { - return; - } self.emergencyModeDuration = newEmergencyModeDuration; emit EmergencyModeDurationSet(newEmergencyModeDuration); } + /// @dev Sets the emergency activation committee address. + /// @param self The storage reference to the Context struct. + /// @param newActivationCommittee The new emergency activation committee address. function setEmergencyActivationCommittee(Context storage self, address newActivationCommittee) internal { if (newActivationCommittee == self.emergencyActivationCommittee) { - return; + revert InvalidEmergencyActivationCommittee(newActivationCommittee); } self.emergencyActivationCommittee = newActivationCommittee; emit EmergencyActivationCommitteeSet(newActivationCommittee); } + /// @dev Sets the emergency execution committee address. + /// @param self The storage reference to the Context struct. + /// @param newExecutionCommittee The new emergency execution committee address. function setEmergencyExecutionCommittee(Context storage self, address newExecutionCommittee) internal { if (newExecutionCommittee == self.emergencyExecutionCommittee) { - return; + revert InvalidEmergencyExecutionCommittee(newExecutionCommittee); } self.emergencyExecutionCommittee = newExecutionCommittee; emit EmergencyExecutionCommitteeSet(newExecutionCommittee); diff --git a/contracts/libraries/EscrowState.sol b/contracts/libraries/EscrowState.sol index 9b6fd842..5c5b14b0 100644 --- a/contracts/libraries/EscrowState.sol +++ b/contracts/libraries/EscrowState.sol @@ -18,6 +18,7 @@ enum State { RageQuitEscrow } +/// @title EscrowState /// @notice Represents the logic to manipulate the state of the Escrow library EscrowState { // --- @@ -28,13 +29,13 @@ library EscrowState { error UnexpectedState(State value); error RageQuitExtraTimelockNotStarted(); error WithdrawalsTimelockNotPassed(); - error BatchesCreationNotInProgress(); + error InvalidMinAssetsLockDuration(Duration newMinAssetsLockDuration); // --- // Events // --- - event RageQuitTimelockStarted(); + event RageQuitTimelockStarted(Timestamp startedAt); event EscrowStateChanged(State from, State to); event RageQuitStarted(Duration rageQuitExtensionDelay, Duration rageQuitWithdrawalsTimelock); event MinAssetsLockDurationSet(Duration newAssetsLockDuration); @@ -59,12 +60,19 @@ library EscrowState { Duration rageQuitWithdrawalsTimelock; } + /// @notice Initializes the Escrow state to SignallingEscrow + /// @param self The context of the Escrow instance + /// @param minAssetsLockDuration The minimum assets lock duration function initialize(Context storage self, Duration minAssetsLockDuration) internal { _checkState(self, State.NotInitialized); _setState(self, State.SignallingEscrow); _setMinAssetsLockDuration(self, minAssetsLockDuration); } + /// @notice Starts the rage quit process + /// @param self The context of the Escrow instance + /// @param rageQuitExtensionDelay The delay period for the rage quit extension + /// @param rageQuitWithdrawalsTimelock The timelock period for rage quit withdrawals function startRageQuit( Context storage self, Duration rageQuitExtensionDelay, @@ -77,14 +85,19 @@ library EscrowState { emit RageQuitStarted(rageQuitExtensionDelay, rageQuitWithdrawalsTimelock); } + /// @notice Starts the rage quit extension delay + /// @param self The context of the Escrow instance function startRageQuitExtensionDelay(Context storage self) internal { self.rageQuitExtensionDelayStartedAt = Timestamps.now(); - emit RageQuitTimelockStarted(); + emit RageQuitTimelockStarted(self.rageQuitExtensionDelayStartedAt); } + /// @notice Sets the minimum assets lock duration + /// @param self The context of the Escrow instance + /// @param newMinAssetsLockDuration The new minimum assets lock duration function setMinAssetsLockDuration(Context storage self, Duration newMinAssetsLockDuration) internal { if (self.minAssetsLockDuration == newMinAssetsLockDuration) { - return; + revert InvalidMinAssetsLockDuration(newMinAssetsLockDuration); } _setMinAssetsLockDuration(self, newMinAssetsLockDuration); } @@ -93,20 +106,28 @@ library EscrowState { // Checks // --- + /// @notice Checks if the Escrow is in the SignallingEscrow state + /// @param self The context of the Escrow instance function checkSignallingEscrow(Context storage self) internal view { _checkState(self, State.SignallingEscrow); } + /// @notice Checks if the Escrow is in the RageQuitEscrow state + /// @param self The context of the Escrow instance function checkRageQuitEscrow(Context storage self) internal view { _checkState(self, State.RageQuitEscrow); } + /// @notice Checks if batch claiming is in progress + /// @param self The context of the Escrow instance function checkBatchesClaimingInProgress(Context storage self) internal view { if (!self.rageQuitExtensionDelayStartedAt.isZero()) { revert ClaimingIsFinished(); } } + /// @notice Checks if the withdrawals timelock has passed + /// @param self The context of the Escrow instance function checkWithdrawalsTimelockPassed(Context storage self) internal view { if (self.rageQuitExtensionDelayStartedAt.isZero()) { revert RageQuitExtraTimelockNotStarted(); @@ -120,16 +141,26 @@ library EscrowState { // --- // Getters // --- + + /// @notice Checks if the rage quit extension delay has started + /// @param self The context of the Escrow instance + /// @return True if the rage quit extension delay has started, false otherwise function isRageQuitExtensionDelayStarted(Context storage self) internal view returns (bool) { return self.rageQuitExtensionDelayStartedAt.isNotZero(); } + /// @notice Checks if the rage quit extension delay has passed + /// @param self The context of the Escrow instance + /// @return True if the rage quit extension delay has passed, false otherwise function isRageQuitExtensionDelayPassed(Context storage self) internal view returns (bool) { Timestamp rageQuitExtensionDelayStartedAt = self.rageQuitExtensionDelayStartedAt; return rageQuitExtensionDelayStartedAt.isNotZero() && Timestamps.now() > self.rageQuitExtensionDelay.addTo(rageQuitExtensionDelayStartedAt); } + /// @notice Checks if the Escrow is in the RageQuitEscrow state + /// @param self The context of the Escrow instance + /// @return True if the Escrow is in the RageQuitEscrow state, false otherwise function isRageQuitEscrow(Context storage self) internal view returns (bool) { return self.state == State.RageQuitEscrow; } @@ -138,18 +169,27 @@ library EscrowState { // Private Methods // --- + /// @notice Checks if the Escrow is in the expected state + /// @param self The context of the Escrow instance + /// @param state The expected state function _checkState(Context storage self, State state) private view { if (self.state != state) { revert UnexpectedState(state); } } + /// @notice Sets the state of the Escrow + /// @param self The context of the Escrow instance + /// @param newState The new state function _setState(Context storage self, State newState) private { State prevState = self.state; self.state = newState; emit EscrowStateChanged(prevState, newState); } + /// @notice Sets the minimum assets lock duration + /// @param self The context of the Escrow instance + /// @param newMinAssetsLockDuration The new minimum assets lock duration function _setMinAssetsLockDuration(Context storage self, Duration newMinAssetsLockDuration) private { self.minAssetsLockDuration = newMinAssetsLockDuration; emit MinAssetsLockDurationSet(newMinAssetsLockDuration); diff --git a/contracts/libraries/Tiebreaker.sol b/contracts/libraries/Tiebreaker.sol index 137a089c..43af793b 100644 --- a/contracts/libraries/Tiebreaker.sol +++ b/contracts/libraries/Tiebreaker.sol @@ -68,12 +68,9 @@ library Tiebreaker { } function setTiebreakerCommittee(Context storage self, address newTiebreakerCommittee) internal { - if (newTiebreakerCommittee == address(0)) { + if (newTiebreakerCommittee == address(0) || newTiebreakerCommittee == self.tiebreakerCommittee) { revert InvalidTiebreakerCommittee(newTiebreakerCommittee); } - if (self.tiebreakerCommittee == newTiebreakerCommittee) { - return; - } self.tiebreakerCommittee = newTiebreakerCommittee; emit TiebreakerCommitteeSet(newTiebreakerCommittee); } @@ -87,13 +84,10 @@ library Tiebreaker { if ( newTiebreakerActivationTimeout < minTiebreakerActivationTimeout || newTiebreakerActivationTimeout > maxTiebreakerActivationTimeout + || newTiebreakerActivationTimeout == self.tiebreakerActivationTimeout ) { revert InvalidTiebreakerActivationTimeout(newTiebreakerActivationTimeout); } - - if (self.tiebreakerActivationTimeout == newTiebreakerActivationTimeout) { - return; - } self.tiebreakerActivationTimeout = newTiebreakerActivationTimeout; emit TiebreakerActivationTimeoutSet(newTiebreakerActivationTimeout); } diff --git a/contracts/libraries/TimelockState.sol b/contracts/libraries/TimelockState.sol index eda71827..05976793 100644 --- a/contracts/libraries/TimelockState.sol +++ b/contracts/libraries/TimelockState.sol @@ -3,6 +3,8 @@ pragma solidity 0.8.26; import {Duration} from "../types/Duration.sol"; +/// @title TimelockState +/// @dev Library for managing the configuration related to emergency protection. library TimelockState { error CallerIsNotGovernance(address caller); error InvalidGovernance(address value); @@ -10,7 +12,6 @@ library TimelockState { error InvalidAfterScheduleDelay(Duration value); event GovernanceSet(address newGovernance); - event AdminExecutorSet(address newAdminExecutor); event AfterSubmitDelaySet(Duration newAfterSubmitDelay); event AfterScheduleDelaySet(Duration newAfterScheduleDelay); @@ -23,55 +24,69 @@ library TimelockState { Duration afterScheduleDelay; } + /// @notice Sets the governance address. + /// @dev Reverts if the new governance address is zero or the same as the current one. + /// @param self The context of the timelock state. + /// @param newGovernance The new governance address. function setGovernance(Context storage self, address newGovernance) internal { - if (newGovernance == address(0)) { + if (newGovernance == address(0) || newGovernance == self.governance) { revert InvalidGovernance(newGovernance); } - if (self.governance == newGovernance) { - return; - } self.governance = newGovernance; emit GovernanceSet(newGovernance); } - function getAfterSubmitDelay(Context storage self) internal view returns (Duration) { - return self.afterSubmitDelay; - } - - function getAfterScheduleDelay(Context storage self) internal view returns (Duration) { - return self.afterScheduleDelay; - } - + /// @notice Sets the after submit delay. + /// @dev Reverts if the new delay is greater than the maximum allowed or the same as the current one. + /// @param self The context of the timelock state. + /// @param newAfterSubmitDelay The new after submit delay. + /// @param maxAfterSubmitDelay The maximum allowed after submit delay. function setAfterSubmitDelay( Context storage self, Duration newAfterSubmitDelay, Duration maxAfterSubmitDelay ) internal { - if (newAfterSubmitDelay > maxAfterSubmitDelay) { - revert InvalidAfterScheduleDelay(newAfterSubmitDelay); - } - if (self.afterSubmitDelay == newAfterSubmitDelay) { - return; + if (newAfterSubmitDelay > maxAfterSubmitDelay || newAfterSubmitDelay == self.afterSubmitDelay) { + revert InvalidAfterSubmitDelay(newAfterSubmitDelay); } self.afterSubmitDelay = newAfterSubmitDelay; emit AfterSubmitDelaySet(newAfterSubmitDelay); } + /// @notice Sets the after schedule delay. + /// @dev Reverts if the new delay is greater than the maximum allowed or the same as the current one. + /// @param self The context of the timelock state. + /// @param newAfterScheduleDelay The new after schedule delay. + /// @param maxAfterScheduleDelay The maximum allowed after schedule delay. function setAfterScheduleDelay( Context storage self, Duration newAfterScheduleDelay, Duration maxAfterScheduleDelay ) internal { - if (newAfterScheduleDelay > maxAfterScheduleDelay) { + if (newAfterScheduleDelay > maxAfterScheduleDelay || newAfterScheduleDelay == self.afterScheduleDelay) { revert InvalidAfterScheduleDelay(newAfterScheduleDelay); } - if (self.afterScheduleDelay == newAfterScheduleDelay) { - return; - } self.afterScheduleDelay = newAfterScheduleDelay; emit AfterScheduleDelaySet(newAfterScheduleDelay); } + /// @notice Gets the after submit delay. + /// @param self The context of the timelock state. + /// @return The current after submit delay. + function getAfterSubmitDelay(Context storage self) internal view returns (Duration) { + return self.afterSubmitDelay; + } + + /// @notice Gets the after schedule delay. + /// @param self The context of the timelock state. + /// @return The current after schedule delay. + function getAfterScheduleDelay(Context storage self) internal view returns (Duration) { + return self.afterScheduleDelay; + } + + /// @notice Checks if the caller is the governance address. + /// @dev Reverts if the caller is not the governance address. + /// @param self The context of the timelock state. function checkCallerIsGovernance(Context storage self) internal view { if (self.governance != msg.sender) { revert CallerIsNotGovernance(msg.sender); diff --git a/test/scenario/happy-path-plan-b.t.sol b/test/scenario/happy-path-plan-b.t.sol index ce38c98a..014594f7 100644 --- a/test/scenario/happy-path-plan-b.t.sol +++ b/test/scenario/happy-path-plan-b.t.sol @@ -121,7 +121,15 @@ contract PlanBSetup is ScenarioTestBlueprint { }); ExternalCall[] memory dualGovernanceLaunchCalls = ExternalCallHelpers.create( - [address(_dualGovernance), address(_timelock), address(_timelock), address(_timelock)], + [ + address(_dualGovernance), + address(_timelock), + address(_timelock), + address(_timelock), + address(_timelock), + address(_timelock), + address(_timelock) + ], [ abi.encodeCall(_dualGovernance.registerProposer, (address(_lido.voting), _timelock.getAdminExecutor())), // Only Dual Governance contract can call the Timelock contract @@ -130,15 +138,15 @@ contract PlanBSetup is ScenarioTestBlueprint { abi.encodeCall(_timelock.deactivateEmergencyMode, ()), // Setup emergency committee for some period of time until the Dual Governance is battle tested abi.encodeCall( - _timelock.setupEmergencyProtection, - ( - address(_emergencyGovernance), - address(_emergencyActivationCommittee), - address(_emergencyExecutionCommittee), - _EMERGENCY_PROTECTION_DURATION.addTo(Timestamps.now()), - _EMERGENCY_MODE_DURATION - ) - ) + _timelock.setEmergencyProtectionActivationCommittee, (address(_emergencyActivationCommittee)) + ), + abi.encodeCall( + _timelock.setEmergencyProtectionExecutionCommittee, (address(_emergencyExecutionCommittee)) + ), + abi.encodeCall( + _timelock.setEmergencyProtectionEndDate, (_EMERGENCY_PROTECTION_DURATION.addTo(Timestamps.now())) + ), + abi.encodeCall(_timelock.setEmergencyModeDuration, (_EMERGENCY_MODE_DURATION)) ] ); @@ -205,22 +213,16 @@ contract PlanBSetup is ScenarioTestBlueprint { }); ExternalCall[] memory dualGovernanceUpdateCalls = ExternalCallHelpers.create( - [address(dualGovernanceV2), address(_timelock), address(_timelock)], + [address(dualGovernanceV2), address(_timelock), address(_timelock), address(_timelock)], [ abi.encodeCall(_dualGovernance.registerProposer, (address(_lido.voting), _timelock.getAdminExecutor())), // Update the controller for timelock abi.encodeCall(_timelock.setGovernance, address(dualGovernanceV2)), // Assembly the emergency committee again, until the new version of Dual Governance is battle tested abi.encodeCall( - _timelock.setupEmergencyProtection, - ( - address(_emergencyGovernance), - address(_emergencyActivationCommittee), - address(_emergencyExecutionCommittee), - _EMERGENCY_PROTECTION_DURATION.addTo(Timestamps.now()), - Durations.from(30 days) - ) - ) + _timelock.setEmergencyProtectionEndDate, (_EMERGENCY_PROTECTION_DURATION.addTo(Timestamps.now())) + ), + abi.encodeCall(_timelock.setEmergencyModeDuration, (Durations.from(30 days))) ] ); diff --git a/test/unit/EmergencyProtectedTimelock.t.sol b/test/unit/EmergencyProtectedTimelock.t.sol index 69b87217..dc208951 100644 --- a/test/unit/EmergencyProtectedTimelock.t.sol +++ b/test/unit/EmergencyProtectedTimelock.t.sol @@ -44,20 +44,18 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { vm.startPrank(_adminExecutor); _timelock.setGovernance(_dualGovernance); - _timelock.setDelays({afterSubmitDelay: Durations.from(3 days), afterScheduleDelay: Durations.from(2 days)}); - _timelock.setupEmergencyProtection( - _emergencyGovernance, - _emergencyActivator, - _emergencyEnactor, - _emergencyProtectionDuration.addTo(Timestamps.now()), - _emergencyModeDuration - ); + _timelock.setupDelays({afterSubmitDelay: Durations.from(3 days), afterScheduleDelay: Durations.from(2 days)}); + _timelock.setEmergencyProtectionActivationCommittee(_emergencyActivator); + _timelock.setEmergencyProtectionExecutionCommittee(_emergencyEnactor); + _timelock.setEmergencyProtectionEndDate(_emergencyProtectionDuration.addTo(Timestamps.now())); + _timelock.setEmergencyModeDuration(_emergencyModeDuration); + _timelock.setEmergencyGovernance(_emergencyGovernance); vm.stopPrank(); } // EmergencyProtectedTimelock.submit() - function testFuzz_stranger_cannot_submit_proposal(address stranger) external { + function testFuzz_submit_RevertOn_ByStranger(address stranger) external { vm.assume(stranger != _dualGovernance); vm.prank(stranger); @@ -66,7 +64,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(_timelock.getProposalsCount(), 0); } - function test_governance_can_submit_proposal() external { + function test_submit_HappyPath() external { vm.prank(_dualGovernance); _timelock.submit(_adminExecutor, _getMockTargetRegularStaffCalls(address(_targetMock))); @@ -78,7 +76,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { // EmergencyProtectedTimelock.schedule() - function test_governance_can_schedule_proposal() external { + function test_schedule_HappyPath() external { _submitProposal(); assertEq(_timelock.getProposalsCount(), 1); @@ -91,7 +89,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(proposal.status, ProposalStatus.Scheduled); } - function testFuzz_stranger_cannot_schedule_proposal(address stranger) external { + function testFuzz_schedule_RevertOn_ByStranger(address stranger) external { vm.assume(stranger != _dualGovernance); vm.assume(stranger != address(0)); @@ -108,7 +106,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { // EmergencyProtectedTimelock.execute() - function testFuzz_anyone_can_execute_proposal(address stranger) external { + function testFuzz_execute_HappyPath(address stranger) external { vm.assume(stranger != _dualGovernance); vm.assume(stranger != address(0)); @@ -128,7 +126,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(proposal.status, ProposalStatus.Executed); } - function test_cannot_execute_proposal_if_emergency_mode_active() external { + function test_execute_RevertOn_EmergencyModeIsActive() external { _submitProposal(); assertEq(_timelock.getProposalsCount(), 1); @@ -149,7 +147,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { // EmergencyProtectedTimelock.cancelAllNonExecutedProposals() - function test_governance_can_cancel_all_non_executed_proposals() external { + function test_cancelAllNonExecutedProposals_HappyPath() external { _submitProposal(); _submitProposal(); @@ -176,7 +174,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(proposal2.status, ProposalStatus.Cancelled); } - function testFuzz_stranger_cannot_cancel_all_non_executed_proposals(address stranger) external { + function testFuzz_cancelAllNonExecutedProposals_RevertOn_ByStranger(address stranger) external { vm.assume(stranger != _dualGovernance); vm.assume(stranger != address(0)); @@ -186,9 +184,34 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { _timelock.cancelAllNonExecutedProposals(); } + function testFuzz_setupDelays_HappyPath(Duration afterSubmitDelay, Duration afterScheduleDelay) external { + vm.assume( + afterSubmitDelay != _timelock.getAfterSubmitDelay() && afterSubmitDelay < _timelock.MAX_AFTER_SUBMIT_DELAY() + ); + vm.assume( + afterScheduleDelay != _timelock.getAfterScheduleDelay() + && afterScheduleDelay < _timelock.MAX_AFTER_SCHEDULE_DELAY() + ); + + vm.prank(_adminExecutor); + _timelock.setupDelays({afterSubmitDelay: afterSubmitDelay, afterScheduleDelay: afterScheduleDelay}); + + assertEq(_timelock.getAfterSubmitDelay(), afterSubmitDelay); + assertEq(_timelock.getAfterScheduleDelay(), afterScheduleDelay); + } + + function test_setupDelays_RevertOn_ByStranger(address stranger) external { + vm.assume(stranger != _adminExecutor); + vm.assume(stranger != address(0)); + + vm.prank(stranger); + vm.expectRevert(abi.encodeWithSelector(EmergencyProtectedTimelock.CallerIsNotAdminExecutor.selector, stranger)); + _timelock.setupDelays({afterSubmitDelay: Durations.from(1 days), afterScheduleDelay: Durations.from(1 days)}); + } + // EmergencyProtectedTimelock.transferExecutorOwnership() - function testFuzz_admin_executor_can_transfer_executor_ownership(address newOwner) external { + function testFuzz_transferExecutorOwnership_HappyPath(address newOwner) external { vm.assume(newOwner != _adminExecutor); vm.assume(newOwner != address(0)); @@ -206,7 +229,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(executor.owner(), newOwner); } - function test_stranger_cannot_transfer_executor_ownership(address stranger) external { + function test_transferExecutorOwnership_RevertOn_ByStranger(address stranger) external { vm.assume(stranger != _adminExecutor); vm.prank(stranger); @@ -216,7 +239,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { // EmergencyProtectedTimelock.setGovernance() - function testFuzz_admin_executor_can_set_governance(address newGovernance) external { + function testFuzz_setGovernance_HappyPath(address newGovernance) external { vm.assume(newGovernance != _dualGovernance); vm.assume(newGovernance != address(0)); @@ -234,23 +257,22 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(entries.length, 1); } - function test_cannot_set_governance_to_zero() external { + function test_setGovernance_RevertOn_ZeroAddress() external { vm.prank(_adminExecutor); vm.expectRevert(abi.encodeWithSelector(TimelockState.InvalidGovernance.selector, address(0))); _timelock.setGovernance(address(0)); } - // TODO: Update test after the convention about return/revert is resolved - // function test_cannot_set_governance_to_the_same_address() external { - // address currentGovernance = _timelock.getGovernance(); - // vm.prank(_adminExecutor); - // vm.expectRevert(abi.encodeWithSelector(TimelockState.InvalidGovernance.selector, _dualGovernance)); - // _timelock.setGovernance(currentGovernance); + function test_setGovernance_RevertOn_SameAddress() external { + address currentGovernance = _timelock.getGovernance(); + vm.prank(_adminExecutor); + vm.expectRevert(abi.encodeWithSelector(TimelockState.InvalidGovernance.selector, _dualGovernance)); + _timelock.setGovernance(currentGovernance); - // assertEq(_timelock.getGovernance(), currentGovernance); - // } + assertEq(_timelock.getGovernance(), currentGovernance); + } - function testFuzz_stranger_cannot_set_governance(address stranger) external { + function testFuzz_setGovernance_RevertOn_ByStranger(address stranger) external { vm.assume(stranger != _adminExecutor); vm.prank(stranger); @@ -260,14 +282,14 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { // EmergencyProtectedTimelock.activateEmergencyMode() - function test_emergency_activator_can_activate_emergency_mode() external { + function test_activateEmergencyMode_HappyPath() external { vm.prank(_emergencyActivator); _timelock.activateEmergencyMode(); assertEq(_isEmergencyStateActivated(), true); } - function testFuzz_stranger_cannot_activate_emergency_mode(address stranger) external { + function testFuzz_activateEmergencyMode_RevertOn_ByStranger(address stranger) external { vm.assume(stranger != _emergencyActivator); vm.assume(stranger != address(0)); @@ -280,7 +302,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(_isEmergencyStateActivated(), false); } - function test_cannot_activate_emergency_mode_if_already_active() external { + function test_activateEmergencyMode_RevertOn_AlreadyActive() external { _activateEmergencyMode(); assertEq(_isEmergencyStateActivated(), true); @@ -294,7 +316,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { // EmergencyProtectedTimelock.emergencyExecute() - function test_emergency_executior_can_execute_proposal() external { + function test_emergencyExecute_HappyPath() external { _submitProposal(); assertEq(_timelock.getProposalsCount(), 1); @@ -316,7 +338,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(proposal.status, ProposalStatus.Executed); } - function test_cannot_emergency_execute_proposal_if_mode_not_activated() external { + function test_emergencyExecute_RevertOn_ModeNotActive() external { vm.startPrank(_dualGovernance); _timelock.submit(_adminExecutor, _getMockTargetRegularStaffCalls(address(_targetMock))); @@ -335,7 +357,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { _timelock.emergencyExecute(1); } - function testFuzz_stranger_cannot_emergency_execute_proposal(address stranger) external { + function testFuzz_emergencyExecute_RevertOn_ByStranger(address stranger) external { vm.assume(stranger != _emergencyEnactor); vm.assume(stranger != address(0)); @@ -362,7 +384,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { // EmergencyProtectedTimelock.deactivateEmergencyMode() - function test_admin_executor_can_deactivate_emergency_mode_if_delay_not_passed() external { + function test_deactivateEmergencyMode_HappyPath() external { _submitProposal(); _activateEmergencyMode(); @@ -372,7 +394,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(_isEmergencyStateActivated(), false); } - function test_after_deactivation_all_proposals_are_cancelled() external { + function test_deactivateEmergencyMode_AllProposalsCancelled() external { _submitProposal(); assertEq(_timelock.getProposalsCount(), 1); @@ -388,7 +410,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(proposal.status, ProposalStatus.Cancelled); } - function testFuzz_stranger_can_deactivate_emergency_mode_if_passed(address stranger) external { + function testFuzz_deactivateEmergencyMode_HappyPath_ByStranger(address stranger) external { vm.assume(stranger != _adminExecutor); _activateEmergencyMode(); @@ -404,7 +426,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(_isEmergencyStateActivated(), false); } - function testFuzz_cannot_deactivate_emergency_mode_if_not_activated(address stranger) external { + function testFuzz_deactivateEmergencyMode_RevertOn_ModeNotActivated(address stranger) external { vm.assume(stranger != _adminExecutor); vm.prank(stranger); @@ -416,7 +438,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { _timelock.deactivateEmergencyMode(); } - function testFuzz_stranger_cannot_deactivate_emergency_mode_if_not_passed(address stranger) external { + function testFuzz_deactivateEmergencyMode_RevertOn_ByStranger_ModeNotExpired(address stranger) external { vm.assume(stranger != _adminExecutor); _activateEmergencyMode(); @@ -429,7 +451,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { // EmergencyProtectedTimelock.emergencyReset() - function test_execution_committee_can_emergency_reset() external { + function test_emergencyReset_HappyPath() external { _activateEmergencyMode(); assertEq(_isEmergencyStateActivated(), true); assertEq(_timelock.isEmergencyProtectionEnabled(), true); @@ -450,7 +472,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(newState.emergencyModeEndsAfter, Timestamps.ZERO); } - function test_after_emergency_reset_all_proposals_are_cancelled() external { + function test_emergencyReset_HappyPath_AllProposalsCancelled() external { _submitProposal(); _activateEmergencyMode(); @@ -464,7 +486,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(proposal.status, ProposalStatus.Cancelled); } - function testFuzz_stranger_cannot_emergency_reset_governance(address stranger) external { + function testFuzz_emergencyReset_RevertOn_ByStranger(address stranger) external { vm.assume(stranger != _emergencyEnactor); vm.assume(stranger != address(0)); @@ -481,7 +503,7 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(_isEmergencyStateActivated(), true); } - function test_cannot_emergency_reset_if_emergency_mode_not_activated() external { + function test_emergencyReset_RevertOn_ModeNotActivated() external { assertEq(_isEmergencyStateActivated(), false); EmergencyProtection.Context memory state = _timelock.getEmergencyProtectionContext(); @@ -500,53 +522,119 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertFalse(_timelock.isEmergencyModeActive()); } - // EmergencyProtectedTimelock.setupEmergencyProtection() + // EmergencyProtectedTimelock.setEmergencyProtectionActivationCommittee() - function test_admin_executor_can_set_emenrgency_protection() external { + function test_setActivationCommittee_HappyPath() external { EmergencyProtectedTimelock _localTimelock = _deployEmergencyProtectedTimelock(); - vm.prank(_adminExecutor); - _localTimelock.setupEmergencyProtection( - _emergencyGovernance, - _emergencyActivator, - _emergencyEnactor, - _emergencyProtectionDuration.addTo(Timestamps.now()), - _emergencyModeDuration - ); + vm.startPrank(_adminExecutor); + _localTimelock.setEmergencyProtectionActivationCommittee(_emergencyActivator); + vm.stopPrank(); EmergencyProtection.Context memory state = _timelock.getEmergencyProtectionContext(); assertEq(state.emergencyActivationCommittee, _emergencyActivator); - assertEq(state.emergencyExecutionCommittee, _emergencyEnactor); - assertEq(state.emergencyProtectionEndsAfter, _emergencyProtectionDuration.addTo(Timestamps.now())); - assertEq(state.emergencyModeDuration, _emergencyModeDuration); - assertEq(state.emergencyModeEndsAfter, Timestamps.ZERO); assertFalse(_timelock.isEmergencyModeActive()); } - function testFuzz_stranger_cannot_set_emergency_protection(address stranger) external { + function testFuzz_setActivationCommittee_RevertOn_ByStranger(address stranger) external { vm.assume(stranger != _adminExecutor); - vm.assume(stranger != address(0)); - EmergencyProtectedTimelock _localTimelock = _deployEmergencyProtectedTimelock(); - vm.prank(stranger); vm.expectRevert(abi.encodeWithSelector(EmergencyProtectedTimelock.CallerIsNotAdminExecutor.selector, stranger)); - _localTimelock.setupEmergencyProtection( - _emergencyGovernance, - _emergencyActivator, - _emergencyEnactor, - _emergencyProtectionDuration.addTo(Timestamps.now()), - _emergencyModeDuration - ); + vm.prank(stranger); + _localTimelock.setEmergencyProtectionActivationCommittee(_emergencyActivator); EmergencyProtection.Context memory state = _localTimelock.getEmergencyProtectionContext(); assertEq(state.emergencyActivationCommittee, address(0)); + assertFalse(_localTimelock.isEmergencyModeActive()); + } + + // EmergencyProtectedTimelock.setEmergencyProtectionExecutionCommittee() + + function test_setExecutionCommittee_HappyPath() external { + EmergencyProtectedTimelock _localTimelock = _deployEmergencyProtectedTimelock(); + + vm.startPrank(_adminExecutor); + _localTimelock.setEmergencyProtectionExecutionCommittee(_emergencyEnactor); + vm.stopPrank(); + + EmergencyProtection.Context memory state = _localTimelock.getEmergencyProtectionContext(); + + assertEq(state.emergencyExecutionCommittee, _emergencyEnactor); + assertFalse(_localTimelock.isEmergencyModeActive()); + } + + function testFuzz_setExecutionCommittee_RevertOn_ByStranger(address stranger) external { + vm.assume(stranger != _adminExecutor); + EmergencyProtectedTimelock _localTimelock = _deployEmergencyProtectedTimelock(); + + vm.expectRevert(abi.encodeWithSelector(EmergencyProtectedTimelock.CallerIsNotAdminExecutor.selector, stranger)); + vm.prank(stranger); + _localTimelock.setEmergencyProtectionExecutionCommittee(_emergencyEnactor); + + EmergencyProtection.Context memory state = _localTimelock.getEmergencyProtectionContext(); + assertEq(state.emergencyExecutionCommittee, address(0)); + assertFalse(_localTimelock.isEmergencyModeActive()); + } + + // EmergencyProtectedTimelock.setEmergencyProtectionEndDate() + + function test_setProtectionEndDate_HappyPath() external { + EmergencyProtectedTimelock _localTimelock = _deployEmergencyProtectedTimelock(); + + vm.startPrank(_adminExecutor); + _localTimelock.setEmergencyProtectionEndDate(_emergencyProtectionDuration.addTo(Timestamps.now())); + vm.stopPrank(); + + EmergencyProtection.Context memory state = _localTimelock.getEmergencyProtectionContext(); + + assertEq(state.emergencyProtectionEndsAfter, _emergencyProtectionDuration.addTo(Timestamps.now())); + assertFalse(_localTimelock.isEmergencyModeActive()); + } + + function testFuzz_setProtectionEndDate_RevertOn_ByStranger(address stranger) external { + vm.assume(stranger != _adminExecutor); + EmergencyProtectedTimelock _localTimelock = _deployEmergencyProtectedTimelock(); + + vm.expectRevert(abi.encodeWithSelector(EmergencyProtectedTimelock.CallerIsNotAdminExecutor.selector, stranger)); + vm.prank(stranger); + _localTimelock.setEmergencyProtectionEndDate(_emergencyProtectionDuration.addTo(Timestamps.now())); + + EmergencyProtection.Context memory state = _localTimelock.getEmergencyProtectionContext(); + assertEq(state.emergencyProtectionEndsAfter, Timestamps.ZERO); + assertFalse(_localTimelock.isEmergencyModeActive()); + } + + // EmergencyProtectedTimelock.setEmergencyModeDuration() + + function test_setModeDuration_HappyPath() external { + EmergencyProtectedTimelock _localTimelock = _deployEmergencyProtectedTimelock(); + + vm.startPrank(_adminExecutor); + _localTimelock.setEmergencyModeDuration(_emergencyModeDuration); + vm.stopPrank(); + + EmergencyProtection.Context memory state = _localTimelock.getEmergencyProtectionContext(); + + assertEq(state.emergencyModeDuration, _emergencyModeDuration); + assertFalse(_localTimelock.isEmergencyModeActive()); + } + + function testFuzz_setModeDuration_RevertOn_ByStranger(address stranger) external { + vm.assume(stranger != _adminExecutor); + EmergencyProtectedTimelock _localTimelock = _deployEmergencyProtectedTimelock(); + + vm.expectRevert(abi.encodeWithSelector(EmergencyProtectedTimelock.CallerIsNotAdminExecutor.selector, stranger)); + vm.prank(stranger); + _localTimelock.setEmergencyModeDuration(_emergencyModeDuration); + + EmergencyProtection.Context memory state = _localTimelock.getEmergencyProtectionContext(); + assertEq(state.emergencyModeDuration, Durations.ZERO); - assertEq(state.emergencyModeEndsAfter, Timestamps.ZERO); assertFalse(_localTimelock.isEmergencyModeActive()); } @@ -557,14 +645,12 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(_localTimelock.isEmergencyProtectionEnabled(), false); - vm.prank(_adminExecutor); - _localTimelock.setupEmergencyProtection( - _emergencyGovernance, - _emergencyActivator, - _emergencyEnactor, - _emergencyProtectionDuration.addTo(Timestamps.now()), - _emergencyModeDuration - ); + vm.startPrank(_adminExecutor); + _localTimelock.setEmergencyProtectionActivationCommittee(_emergencyActivator); + _localTimelock.setEmergencyProtectionExecutionCommittee(_emergencyEnactor); + _localTimelock.setEmergencyProtectionEndDate(_emergencyProtectionDuration.addTo(Timestamps.now())); + _localTimelock.setEmergencyModeDuration(_emergencyModeDuration); + vm.stopPrank(); assertEq(_localTimelock.isEmergencyProtectionEnabled(), true); @@ -584,14 +670,13 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(_localTimelock.isEmergencyProtectionEnabled(), false); - vm.prank(_adminExecutor); - _localTimelock.setupEmergencyProtection( - _emergencyGovernance, - _emergencyActivator, - _emergencyEnactor, - _emergencyProtectionDuration.addTo(Timestamps.now()), - _emergencyModeDuration - ); + vm.startPrank(_adminExecutor); + _localTimelock.setEmergencyProtectionActivationCommittee(_emergencyActivator); + _localTimelock.setEmergencyProtectionExecutionCommittee(_emergencyEnactor); + _localTimelock.setEmergencyProtectionEndDate(_emergencyProtectionDuration.addTo(Timestamps.now())); + _localTimelock.setEmergencyModeDuration(_emergencyModeDuration); + _localTimelock.setEmergencyGovernance(_emergencyGovernance); + vm.stopPrank(); assertEq(_localTimelock.isEmergencyProtectionEnabled(), true); @@ -620,14 +705,12 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { assertEq(state.emergencyModeDuration, Durations.ZERO); assertEq(state.emergencyModeEndsAfter, Timestamps.ZERO); - vm.prank(_adminExecutor); - _localTimelock.setupEmergencyProtection( - _emergencyGovernance, - _emergencyActivator, - _emergencyEnactor, - _emergencyProtectionDuration.addTo(Timestamps.now()), - _emergencyModeDuration - ); + vm.startPrank(_adminExecutor); + _localTimelock.setEmergencyProtectionActivationCommittee(_emergencyActivator); + _localTimelock.setEmergencyProtectionExecutionCommittee(_emergencyEnactor); + _localTimelock.setEmergencyProtectionEndDate(_emergencyProtectionDuration.addTo(Timestamps.now())); + _localTimelock.setEmergencyModeDuration(_emergencyModeDuration); + vm.stopPrank(); state = _localTimelock.getEmergencyProtectionContext(); @@ -666,14 +749,13 @@ contract EmergencyProtectedTimelockUnitTests is UnitTest { function test_get_emergency_state_reset() external { EmergencyProtectedTimelock _localTimelock = _deployEmergencyProtectedTimelock(); - vm.prank(_adminExecutor); - _localTimelock.setupEmergencyProtection( - _emergencyGovernance, - _emergencyActivator, - _emergencyEnactor, - _emergencyProtectionDuration.addTo(Timestamps.now()), - _emergencyModeDuration - ); + vm.startPrank(_adminExecutor); + _localTimelock.setEmergencyProtectionActivationCommittee(_emergencyActivator); + _localTimelock.setEmergencyProtectionExecutionCommittee(_emergencyEnactor); + _localTimelock.setEmergencyProtectionEndDate(_emergencyProtectionDuration.addTo(Timestamps.now())); + _localTimelock.setEmergencyModeDuration(_emergencyModeDuration); + _localTimelock.setEmergencyGovernance(_emergencyGovernance); + vm.stopPrank(); vm.prank(_emergencyActivator); _localTimelock.activateEmergencyMode(); diff --git a/test/unit/HashConsensus.t.sol b/test/unit/HashConsensus.t.sol index c9f22039..966c7a52 100644 --- a/test/unit/HashConsensus.t.sol +++ b/test/unit/HashConsensus.t.sol @@ -260,6 +260,16 @@ abstract contract HashConsensusUnitTest is UnitTest { _hashConsensus.setTimelockDuration(newTimelockDuration); } + function test_setTimelockDurationRevertsIfValueIsSame() public { + uint256 newTimelockDuration = 300; + + vm.startPrank(_owner); + _hashConsensus.setTimelockDuration(newTimelockDuration); + + vm.expectRevert(abi.encodeWithSelector(HashConsensus.InvalidTimelockDuration.selector, newTimelockDuration)); + _hashConsensus.setTimelockDuration(newTimelockDuration); + } + function testTimelockDurationEventEmitted() public { uint256 newTimelockDuration = 300; @@ -307,6 +317,16 @@ abstract contract HashConsensusUnitTest is UnitTest { _hashConsensus.setQuorum(invalidQuorum); } + function test_setQuorumRevertsIfQuorumIsSame() public { + uint256 invalidQuorum = 2; + + vm.startPrank(_owner); + _hashConsensus.setQuorum(invalidQuorum); + + vm.expectRevert(abi.encodeWithSignature("InvalidQuorum()")); + _hashConsensus.setQuorum(invalidQuorum); + } + function test_quorumEventEmitted() public { uint256 newQuorum = 3; diff --git a/test/unit/libraries/EmergencyProtection.t.sol b/test/unit/libraries/EmergencyProtection.t.sol index 02856a37..0f5faf9b 100644 --- a/test/unit/libraries/EmergencyProtection.t.sol +++ b/test/unit/libraries/EmergencyProtection.t.sol @@ -1,352 +1,223 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; -import {Vm} from "forge-std/Test.sol"; - -import {Timestamps} from "contracts/types/Timestamp.sol"; +import {Timestamps, Timestamp} from "contracts/types/Timestamp.sol"; import {Duration, Durations} from "contracts/types/Duration.sol"; - import {EmergencyProtection} from "contracts/libraries/EmergencyProtection.sol"; import {UnitTest} from "test/utils/unit-test.sol"; -contract EmergencyProtectionUnitTests is UnitTest { - using EmergencyProtection for EmergencyProtection.Context; - - address internal _emergencyGovernance = makeAddr("EMERGENCY_GOVERNANCE"); - - EmergencyProtection.Context internal _emergencyProtection; - - function testFuzz_setup_emergency_protection( - address activationCommittee, - address executionCommittee, - address emergencyGovernance, - Duration protectionDuration, - Duration duration - ) external { - vm.assume(protectionDuration > Durations.ZERO); - vm.assume(duration > Durations.ZERO); - // vm.assume(activationCommittee != address(0)); - // vm.assume(executionCommittee != address(0)); - uint256 expectedLogEntiresCount = 2; - if (emergencyGovernance != address(0)) { - vm.expectEmit(); - emit EmergencyProtection.EmergencyGovernanceSet(emergencyGovernance); - expectedLogEntiresCount += 1; - } - - if (activationCommittee != address(0)) { - vm.expectEmit(); - emit EmergencyProtection.EmergencyActivationCommitteeSet(activationCommittee); - expectedLogEntiresCount += 1; - } - if (executionCommittee != address(0)) { - vm.expectEmit(); - emit EmergencyProtection.EmergencyExecutionCommitteeSet(executionCommittee); - expectedLogEntiresCount += 1; - } - vm.expectEmit(); - emit EmergencyProtection.EmergencyProtectionEndDateSet(protectionDuration.addTo(Timestamps.now())); - vm.expectEmit(); - emit EmergencyProtection.EmergencyModeDurationSet(duration); - - vm.recordLogs(); - - _setup(emergencyGovernance, activationCommittee, executionCommittee, protectionDuration, duration); +contract EmergencyProtectionTest is UnitTest { + EmergencyProtection.Context ctx; - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, expectedLogEntiresCount); + address emergencyGovernance = address(0x1); + address emergencyActivationCommittee = address(0x2); + address emergencyExecutionCommittee = address(0x3); - assertEq(_emergencyProtection.emergencyGovernance, emergencyGovernance); - assertEq(_emergencyProtection.emergencyActivationCommittee, activationCommittee); - assertEq(_emergencyProtection.emergencyExecutionCommittee, executionCommittee); - assertEq(_emergencyProtection.emergencyProtectionEndsAfter, protectionDuration.addTo(Timestamps.now())); - assertEq(_emergencyProtection.emergencyModeDuration, duration); - assertEq(_emergencyProtection.emergencyModeEndsAfter, Timestamps.ZERO); + function setUp() external { + // Setup initial values + ctx.emergencyGovernance = emergencyGovernance; + ctx.emergencyActivationCommittee = emergencyActivationCommittee; + ctx.emergencyExecutionCommittee = emergencyExecutionCommittee; + ctx.emergencyModeDuration = Duration.wrap(3600); + ctx.emergencyProtectionEndsAfter = Timestamps.from(block.timestamp + 86400); } - function test_setup_same_activation_committee() external { - Duration protectionDuration = Durations.from(100 seconds); - Duration emergencyModeDuration = Durations.from(100 seconds); - address activationCommittee = makeAddr("activationCommittee"); - - _setup(_emergencyGovernance, activationCommittee, address(0x2), protectionDuration, emergencyModeDuration); - - Duration newProtectionDuration = Durations.from(200 seconds); - Duration newEmergencyModeDuration = Durations.from(300 seconds); - - vm.expectEmit(); - emit EmergencyProtection.EmergencyExecutionCommitteeSet(address(0x3)); - vm.expectEmit(); - emit EmergencyProtection.EmergencyProtectionEndDateSet(newProtectionDuration.addTo(Timestamps.now())); + function test_ActivateEmergencyMode() external { vm.expectEmit(); - emit EmergencyProtection.EmergencyModeDurationSet(newEmergencyModeDuration); - - vm.recordLogs(); - _setup(_emergencyGovernance, activationCommittee, address(0x3), newProtectionDuration, newEmergencyModeDuration); - - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 3); + emit EmergencyProtection.EmergencyModeActivated(); + EmergencyProtection.activateEmergencyMode(ctx); - assertEq(_emergencyProtection.emergencyActivationCommittee, activationCommittee); - assertEq(_emergencyProtection.emergencyExecutionCommittee, address(0x3)); - assertEq(_emergencyProtection.emergencyProtectionEndsAfter, newProtectionDuration.addTo(Timestamps.now())); - assertEq(_emergencyProtection.emergencyModeDuration, newEmergencyModeDuration); - assertEq(_emergencyProtection.emergencyModeEndsAfter, Timestamps.ZERO); + assertTrue(EmergencyProtection.isEmergencyModeActive(ctx)); + assertEq(Timestamp.unwrap(ctx.emergencyModeEndsAfter), block.timestamp + 3600); } - function test_setup_same_execution_committee() external { - Duration protectionDuration = Durations.from(100 seconds); - Duration emergencyModeDuration = Durations.from(100 seconds); - address executionCommittee = makeAddr("executionCommittee"); - - _setup(_emergencyGovernance, address(0x1), executionCommittee, protectionDuration, emergencyModeDuration); - - Duration newProtectionDuration = Durations.from(200 seconds); - Duration newEmergencyModeDuration = Durations.from(300 seconds); - - vm.expectEmit(); - emit EmergencyProtection.EmergencyActivationCommitteeSet(address(0x2)); - vm.expectEmit(); - emit EmergencyProtection.EmergencyProtectionEndDateSet(newProtectionDuration.addTo(Timestamps.now())); - vm.expectEmit(); - emit EmergencyProtection.EmergencyModeDurationSet(newEmergencyModeDuration); - - vm.recordLogs(); - _setup(_emergencyGovernance, address(0x2), executionCommittee, newProtectionDuration, newEmergencyModeDuration); + function test_ActivateEmergencyMode_RevertOn_ProtectionExpired() external { + Duration untilExpiration = + Durations.between(ctx.emergencyProtectionEndsAfter, Timestamps.from(block.timestamp)).plusSeconds(1); - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 3); + _wait(untilExpiration); - assertEq(_emergencyProtection.emergencyActivationCommittee, address(0x2)); - assertEq(_emergencyProtection.emergencyExecutionCommittee, executionCommittee); - assertEq(_emergencyProtection.emergencyProtectionEndsAfter, newProtectionDuration.addTo(Timestamps.now())); - assertEq(_emergencyProtection.emergencyModeDuration, newEmergencyModeDuration); - assertEq(_emergencyProtection.emergencyModeEndsAfter, Timestamps.ZERO); + vm.expectRevert( + abi.encodeWithSelector( + EmergencyProtection.EmergencyProtectionExpired.selector, ctx.emergencyProtectionEndsAfter + ) + ); + EmergencyProtection.activateEmergencyMode(ctx); } - function test_setup_same_protected_till() external { - Duration protectionDuration = Durations.from(100 seconds); - Duration emergencyModeDuration = Durations.from(100 seconds); - - _setup(_emergencyGovernance, address(0x1), address(0x2), protectionDuration, emergencyModeDuration); + function test_DeactivateEmergencyMode() external { + EmergencyProtection.activateEmergencyMode(ctx); - Duration newProtectionDuration = protectionDuration; // the new value is the same as previous one - Duration newEmergencyModeDuration = Durations.from(200 seconds); - - vm.expectEmit(); - emit EmergencyProtection.EmergencyActivationCommitteeSet(address(0x3)); - vm.expectEmit(); - emit EmergencyProtection.EmergencyExecutionCommitteeSet(address(0x4)); vm.expectEmit(); - emit EmergencyProtection.EmergencyModeDurationSet(newEmergencyModeDuration); - - vm.recordLogs(); - _setup(_emergencyGovernance, address(0x3), address(0x4), newProtectionDuration, newEmergencyModeDuration); - - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 3); - - assertEq(_emergencyProtection.emergencyActivationCommittee, address(0x3)); - assertEq(_emergencyProtection.emergencyExecutionCommittee, address(0x4)); - assertEq(_emergencyProtection.emergencyProtectionEndsAfter, protectionDuration.addTo(Timestamps.now())); - assertEq(_emergencyProtection.emergencyModeDuration, newEmergencyModeDuration); - assertEq(_emergencyProtection.emergencyModeEndsAfter, Timestamps.ZERO); + emit EmergencyProtection.EmergencyModeDeactivated(); + EmergencyProtection.deactivateEmergencyMode(ctx); + + assertFalse(EmergencyProtection.isEmergencyModeActive(ctx)); + assertEq(ctx.emergencyActivationCommittee, address(0)); + assertEq(ctx.emergencyExecutionCommittee, address(0)); + assertEq(Timestamp.unwrap(ctx.emergencyProtectionEndsAfter), 0); + assertEq(Timestamp.unwrap(ctx.emergencyModeEndsAfter), 0); + assertEq(Duration.unwrap(ctx.emergencyModeDuration), 0); } - function test_setup_same_emergency_mode_duration() external { - Duration protectionDuration = Durations.from(100 seconds); - Duration emergencyModeDuration = Durations.from(100 seconds); - - _setup(_emergencyGovernance, address(0x1), address(0x2), protectionDuration, emergencyModeDuration); + function test_SetEmergencyGovernance() external { + address newGovernance = address(0x4); - Duration newProtectionDuration = Durations.from(200 seconds); - Duration newEmergencyModeDuration = emergencyModeDuration; // the new value is the same as previous one - - vm.expectEmit(); - emit EmergencyProtection.EmergencyActivationCommitteeSet(address(0x3)); vm.expectEmit(); - emit EmergencyProtection.EmergencyExecutionCommitteeSet(address(0x4)); - vm.expectEmit(); - emit EmergencyProtection.EmergencyProtectionEndDateSet(newProtectionDuration.addTo(Timestamps.now())); - - vm.recordLogs(); - _setup(_emergencyGovernance, address(0x3), address(0x4), newProtectionDuration, newEmergencyModeDuration); - - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 3); + emit EmergencyProtection.EmergencyGovernanceSet(newGovernance); + EmergencyProtection.setEmergencyGovernance(ctx, newGovernance); - assertEq(_emergencyProtection.emergencyActivationCommittee, address(0x3)); - assertEq(_emergencyProtection.emergencyExecutionCommittee, address(0x4)); - assertEq(_emergencyProtection.emergencyProtectionEndsAfter, newProtectionDuration.addTo(Timestamps.now())); - assertEq(_emergencyProtection.emergencyModeDuration, newEmergencyModeDuration); - assertEq(_emergencyProtection.emergencyModeEndsAfter, Timestamps.ZERO); + assertEq(ctx.emergencyGovernance, newGovernance); } - function test_activate_emergency_mode() external { - Duration protectionDuration = Durations.from(100 seconds); - Duration emergencyModeDuration = Durations.from(100 seconds); + function test_SetEmergencyGovernance_RevertOn_SameAddress() external { + vm.expectRevert( + abi.encodeWithSelector(EmergencyProtection.InvalidEmergencyGovernance.selector, emergencyGovernance) + ); + EmergencyProtection.setEmergencyGovernance(ctx, emergencyGovernance); + } - _setup(_emergencyGovernance, address(0x1), address(0x2), protectionDuration, emergencyModeDuration); + function test_SetEmergencyProtectionEndDate() external { + Timestamp newEndDate = Timestamps.from(block.timestamp + 43200); vm.expectEmit(); - emit EmergencyProtection.EmergencyModeActivated(); - - vm.recordLogs(); + emit EmergencyProtection.EmergencyProtectionEndDateSet(newEndDate); + EmergencyProtection.setEmergencyProtectionEndDate(ctx, newEndDate, Duration.wrap(86400)); - _emergencyProtection.activateEmergencyMode(); - - Vm.Log[] memory entries = vm.getRecordedLogs(); - - assertEq(entries.length, 1); - assertEq(_emergencyProtection.emergencyModeEndsAfter, emergencyModeDuration.addTo(Timestamps.now())); + assertEq(Timestamp.unwrap(ctx.emergencyProtectionEndsAfter), block.timestamp + 43200); } - function test_cannot_activate_emergency_mode_if_protected_till_expired() external { - Duration protectionDuration = Durations.from(100 seconds); - Duration emergencyModeDuration = Durations.from(100 seconds); - - _setup(_emergencyGovernance, address(0x1), address(0x2), protectionDuration, emergencyModeDuration); + function test_SetEmergencyProtectionEndDate_RevertOn_InvalidValue() external { + Timestamp invalidEndDate = Timestamps.from(block.timestamp + 90000); - _wait(protectionDuration.plusSeconds(1)); + vm.expectRevert( + abi.encodeWithSelector(EmergencyProtection.InvalidEmergencyProtectionEndDate.selector, invalidEndDate) + ); + EmergencyProtection.setEmergencyProtectionEndDate(ctx, invalidEndDate, Duration.wrap(86400)); vm.expectRevert( abi.encodeWithSelector( - EmergencyProtection.EmergencyProtectionExpired.selector, - _emergencyProtection.emergencyProtectionEndsAfter + EmergencyProtection.InvalidEmergencyProtectionEndDate.selector, ctx.emergencyProtectionEndsAfter ) ); - _emergencyProtection.activateEmergencyMode(); + EmergencyProtection.setEmergencyProtectionEndDate(ctx, ctx.emergencyProtectionEndsAfter, Duration.wrap(86400)); } - function testFuzz_deactivate_emergency_mode( - address activationCommittee, - address executionCommittee, - Duration protectionDuration, - Duration emergencyModeDuration - ) external { - vm.assume(activationCommittee != address(0)); - vm.assume(executionCommittee != address(0)); - - _setup(_emergencyGovernance, activationCommittee, executionCommittee, protectionDuration, emergencyModeDuration); - _emergencyProtection.activateEmergencyMode(); + function test_SetEmergencyModeDuration() external { + Duration newDuration = Duration.wrap(7200); vm.expectEmit(); - emit EmergencyProtection.EmergencyModeDeactivated(); - - vm.recordLogs(); + emit EmergencyProtection.EmergencyModeDurationSet(newDuration); + EmergencyProtection.setEmergencyModeDuration(ctx, newDuration, Duration.wrap(86400)); - _emergencyProtection.deactivateEmergencyMode(); - - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 1); - - assertEq(_emergencyProtection.emergencyActivationCommittee, address(0)); - assertEq(_emergencyProtection.emergencyExecutionCommittee, address(0)); - assertEq(_emergencyProtection.emergencyProtectionEndsAfter, Timestamps.ZERO); - assertEq(_emergencyProtection.emergencyModeDuration, Durations.ZERO); - assertEq(_emergencyProtection.emergencyModeEndsAfter, Timestamps.ZERO); + assertEq(Duration.unwrap(ctx.emergencyModeDuration), 7200); } - function test_is_emergency_mode_activated() external { - assertEq(_emergencyProtection.isEmergencyModeActive(), false); - - Duration protectionDuration = Durations.from(100 seconds); - Duration emergencyModeDuration = Durations.from(100 seconds); - - _setup(_emergencyGovernance, address(0x1), address(0x2), protectionDuration, emergencyModeDuration); - - assertEq(_emergencyProtection.isEmergencyModeActive(), false); + function test_SetEmergencyModeDuration_RevertOn_InvalidValue() external { + Duration invalidDuration = Duration.wrap(90000); - _emergencyProtection.activateEmergencyMode(); - - assertEq(_emergencyProtection.isEmergencyModeActive(), true); - - _emergencyProtection.deactivateEmergencyMode(); + vm.expectRevert( + abi.encodeWithSelector(EmergencyProtection.InvalidEmergencyModeDuration.selector, invalidDuration) + ); + EmergencyProtection.setEmergencyModeDuration(ctx, invalidDuration, Duration.wrap(86400)); - assertEq(_emergencyProtection.isEmergencyModeActive(), false); + vm.expectRevert( + abi.encodeWithSelector(EmergencyProtection.InvalidEmergencyModeDuration.selector, ctx.emergencyModeDuration) + ); + EmergencyProtection.setEmergencyModeDuration(ctx, ctx.emergencyModeDuration, Duration.wrap(86400)); } - function test_is_emergency_mode_passed() external { - assertEq(_emergencyProtection.isEmergencyModeDurationPassed(), false); - - Duration protectionDuration = Durations.from(100 seconds); - Duration emergencyModeDuration = Durations.from(200 seconds); - - _setup(_emergencyGovernance, address(0x1), address(0x2), protectionDuration, emergencyModeDuration); - - assertEq(_emergencyProtection.isEmergencyModeDurationPassed(), false); - - _emergencyProtection.activateEmergencyMode(); + function test_CheckCallerIsEmergencyActivationCommittee() external { + vm.prank(emergencyActivationCommittee); + this.external__checkCallerIsEmergencyActivationCommittee(); + } - assertEq(_emergencyProtection.isEmergencyModeDurationPassed(), false); + function test_CheckCallerIsEmergencyActivationCommittee_RevertOn_Stranger() external { + vm.expectRevert( + abi.encodeWithSelector(EmergencyProtection.CallerIsNotEmergencyActivationCommittee.selector, address(0x5)) + ); + vm.prank(address(0x5)); + this.external__checkCallerIsEmergencyActivationCommittee(); + } - _wait(emergencyModeDuration.plusSeconds(1)); + function test_CheckCallerIsEmergencyExecutionCommittee() external { + vm.prank(emergencyExecutionCommittee); + this.external__checkCallerIsEmergencyExecutionCommittee(); + } - assertEq(_emergencyProtection.isEmergencyModeDurationPassed(), true); + function test_CheckCallerIsEmergencyExecutionCommittee_RevertOn_Stranger() external { + vm.expectRevert( + abi.encodeWithSelector(EmergencyProtection.CallerIsNotEmergencyExecutionCommittee.selector, address(0x5)) + ); + vm.prank(address(0x5)); + this.external__checkCallerIsEmergencyExecutionCommittee(); + } - _emergencyProtection.deactivateEmergencyMode(); + function test_CheckEmergencyMode() external { + EmergencyProtection.activateEmergencyMode(ctx); + EmergencyProtection.checkEmergencyMode(ctx, true); + } - assertEq(_emergencyProtection.isEmergencyModeDurationPassed(), false); + function test_CheckEmergencyMode_RevertOn_NotInEmergencyMode() external { + vm.expectRevert(abi.encodeWithSelector(EmergencyProtection.UnexpectedEmergencyModeState.selector, true)); + EmergencyProtection.checkEmergencyMode(ctx, true); } - function test_is_emergency_protection_enabled() external { - Duration protectionDuration = Durations.from(100 seconds); - Duration emergencyModeDuration = Durations.from(200 seconds); + function test_IsEmergencyModeActive() public { + assertFalse(EmergencyProtection.isEmergencyModeActive(ctx)); + EmergencyProtection.activateEmergencyMode(ctx); + assertTrue(EmergencyProtection.isEmergencyModeActive(ctx)); + } - assertEq(_emergencyProtection.isEmergencyProtectionEnabled(), false); + function test_IsEmergencyModeDurationPassed() public { + assertFalse(EmergencyProtection.isEmergencyModeDurationPassed(ctx)); + EmergencyProtection.activateEmergencyMode(ctx); + assertFalse(EmergencyProtection.isEmergencyModeDurationPassed(ctx)); - _setup(_emergencyGovernance, address(0x1), address(0x2), protectionDuration, emergencyModeDuration); + Duration untilExpiration = + Durations.between(ctx.emergencyModeEndsAfter, Timestamps.from(block.timestamp)).plusSeconds(1); + _wait(untilExpiration); - assertEq(_emergencyProtection.isEmergencyProtectionEnabled(), true); + assertTrue(EmergencyProtection.isEmergencyModeDurationPassed(ctx)); + } - EmergencyProtection.Context memory emergencyState = _emergencyProtection; + function test_IsEmergencyProtectionEnabled() public { + assertTrue(EmergencyProtection.isEmergencyProtectionEnabled(ctx)); - _wait(Durations.between(emergencyState.emergencyProtectionEndsAfter, Timestamps.now())); + Duration untilExpiration = + Durations.between(ctx.emergencyProtectionEndsAfter, Timestamps.from(block.timestamp)).plusSeconds(1); + _wait(untilExpiration); - // _wait(emergencyState.emergencyProtectionEndsAfter.absDiff(Timestamps.now())); + assertFalse(EmergencyProtection.isEmergencyProtectionEnabled(ctx)); + } - EmergencyProtection.activateEmergencyMode(_emergencyProtection); + function test_IsEmergencyProtectionEnabled_WhenEmergencyModeActive() public { + assertTrue(EmergencyProtection.isEmergencyProtectionEnabled(ctx)); + EmergencyProtection.activateEmergencyMode(ctx); + assertTrue(EmergencyProtection.isEmergencyProtectionEnabled(ctx)); - _wait(emergencyModeDuration); + Duration untilExpiration = + Durations.between(ctx.emergencyModeEndsAfter, Timestamps.from(block.timestamp)).plusSeconds(1); + _wait(untilExpiration); - assertEq(_emergencyProtection.isEmergencyProtectionEnabled(), true); + assertTrue(EmergencyProtection.isEmergencyProtectionEnabled(ctx)); - _wait(protectionDuration); + untilExpiration = + Durations.between(ctx.emergencyProtectionEndsAfter, Timestamps.from(block.timestamp)).plusSeconds(1); - assertEq(_emergencyProtection.isEmergencyProtectionEnabled(), true); + assertTrue(EmergencyProtection.isEmergencyProtectionEnabled(ctx)); - EmergencyProtection.deactivateEmergencyMode(_emergencyProtection); + EmergencyProtection.deactivateEmergencyMode(ctx); - assertEq(_emergencyProtection.isEmergencyProtectionEnabled(), false); + assertFalse(EmergencyProtection.isEmergencyProtectionEnabled(ctx)); } - function test_check_emergency_mode_active() external { - vm.expectRevert(abi.encodeWithSelector(EmergencyProtection.UnexpectedEmergencyModeState.selector, [true])); - _emergencyProtection.checkEmergencyMode(true); - _emergencyProtection.checkEmergencyMode(false); - - Duration protectionDuration = Durations.from(100 seconds); - Duration emergencyModeDuration = Durations.from(100 seconds); - - _setup(_emergencyGovernance, address(0x1), address(0x2), protectionDuration, emergencyModeDuration); - _emergencyProtection.activateEmergencyMode(); - - _emergencyProtection.checkEmergencyMode(true); - vm.expectRevert(abi.encodeWithSelector(EmergencyProtection.UnexpectedEmergencyModeState.selector, [true])); + function external__checkCallerIsEmergencyActivationCommittee() external view { + EmergencyProtection.checkCallerIsEmergencyActivationCommittee(ctx); } - function _setup( - address newEmergencyGovernance, - address newEmergencyActivationCommittee, - address newEmergencyExecutionCommittee, - Duration protectionDuration, - Duration emergencyModeDuration - ) internal { - _emergencyProtection.setEmergencyGovernance(newEmergencyGovernance); - _emergencyProtection.setEmergencyActivationCommittee(newEmergencyActivationCommittee); - _emergencyProtection.setEmergencyExecutionCommittee(newEmergencyExecutionCommittee); - _emergencyProtection.setEmergencyProtectionEndDate(protectionDuration.addTo(Timestamps.now()), Durations.MAX); - _emergencyProtection.setEmergencyModeDuration(emergencyModeDuration, Durations.MAX); + function external__checkCallerIsEmergencyExecutionCommittee() external view { + EmergencyProtection.checkCallerIsEmergencyExecutionCommittee(ctx); } } diff --git a/test/utils/SetupDeployment.sol b/test/utils/SetupDeployment.sol index c6464c6f..c90aa848 100644 --- a/test/utils/SetupDeployment.sol +++ b/test/utils/SetupDeployment.sol @@ -260,22 +260,36 @@ abstract contract SetupDeployment is Test { address(_timelock), 0, abi.encodeCall( - _timelock.setupEmergencyProtection, - ( - address(_emergencyGovernance), - address(_emergencyActivationCommittee), - address(_emergencyExecutionCommittee), - _EMERGENCY_PROTECTION_DURATION.addTo(Timestamps.now()), - _EMERGENCY_MODE_DURATION - ) + _timelock.setEmergencyProtectionActivationCommittee, (address(_emergencyActivationCommittee)) ) ); + _adminExecutor.execute( + address(_timelock), + 0, + abi.encodeCall( + _timelock.setEmergencyProtectionExecutionCommittee, (address(_emergencyExecutionCommittee)) + ) + ); + _adminExecutor.execute( + address(_timelock), + 0, + abi.encodeCall( + _timelock.setEmergencyProtectionEndDate, (_EMERGENCY_PROTECTION_DURATION.addTo(Timestamps.now())) + ) + ); + _adminExecutor.execute( + address(_timelock), 0, abi.encodeCall(_timelock.setEmergencyModeDuration, (_EMERGENCY_MODE_DURATION)) + ); + + _adminExecutor.execute( + address(_timelock), 0, abi.encodeCall(_timelock.setEmergencyGovernance, (address(_emergencyGovernance))) + ); } } function _finalizeEmergencyProtectedTimelockDeploy(IGovernance governance) internal { _adminExecutor.execute( - address(_timelock), 0, abi.encodeCall(_timelock.setDelays, (_AFTER_SUBMIT_DELAY, _AFTER_SCHEDULE_DELAY)) + address(_timelock), 0, abi.encodeCall(_timelock.setupDelays, (_AFTER_SUBMIT_DELAY, _AFTER_SCHEDULE_DELAY)) ); _adminExecutor.execute(address(_timelock), 0, abi.encodeCall(_timelock.setGovernance, (address(governance)))); _adminExecutor.transferOwnership(address(_timelock)); diff --git a/test/utils/executor-calls.sol b/test/utils/executor-calls.sol index c5ca8600..610d6035 100644 --- a/test/utils/executor-calls.sol +++ b/test/utils/executor-calls.sol @@ -35,6 +35,27 @@ library ExternalCallHelpers { } } + function create(ExternalCall[5] memory calls) internal pure returns (ExternalCall[] memory res) { + res = new ExternalCall[](5); + for (uint256 i = 0; i < 5; ++i) { + res[i] = calls[i]; + } + } + + function create(ExternalCall[6] memory calls) internal pure returns (ExternalCall[] memory res) { + res = new ExternalCall[](6); + for (uint256 i = 0; i < 6; ++i) { + res[i] = calls[i]; + } + } + + function create(ExternalCall[7] memory calls) internal pure returns (ExternalCall[] memory res) { + res = new ExternalCall[](7); + for (uint256 i = 0; i < 7; ++i) { + res[i] = calls[i]; + } + } + // calls with value equal to 0 function create( @@ -79,6 +100,39 @@ library ExternalCallHelpers { } } + function create( + address[5] memory targets, + bytes[5] memory payloads + ) internal pure returns (ExternalCall[] memory res) { + res = new ExternalCall[](5); + for (uint256 i = 0; i < 5; ++i) { + res[i].target = targets[i]; + res[i].payload = payloads[i]; + } + } + + function create( + address[6] memory targets, + bytes[6] memory payloads + ) internal pure returns (ExternalCall[] memory res) { + res = new ExternalCall[](6); + for (uint256 i = 0; i < 6; ++i) { + res[i].target = targets[i]; + res[i].payload = payloads[i]; + } + } + + function create( + address[7] memory targets, + bytes[7] memory payloads + ) internal pure returns (ExternalCall[] memory res) { + res = new ExternalCall[](7); + for (uint256 i = 0; i < 7; ++i) { + res[i].target = targets[i]; + res[i].payload = payloads[i]; + } + } + function create( address[10] memory targets, bytes[10] memory payloads