Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore committee tests #76

Merged
merged 3 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions contracts/committees/EmergencyActivationCommittee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import {HashConsensus} from "./HashConsensus.sol";

interface IEmergencyProtectedTimelock {
function emergencyActivate() external;
function activateEmergencyMode() external;
}

/// @title Emergency Activation Committee Contract
Expand All @@ -27,15 +27,15 @@

/// @notice Approves the emergency activation by casting a vote
/// @dev Only callable by committee members
function approveEmergencyActivate() public onlyMember {
function approveActivateEmergencyMode() public onlyMember {
_vote(EMERGENCY_ACTIVATION_HASH, true);
}

/// @notice Gets the current state of the emergency activation vote
/// @return support The number of votes in support of the activation
/// @return execuitionQuorum The required number of votes for execution
/// @return isExecuted Whether the activation has been executed
function getEmergencyActivateState()
function getActivateEmergencyModeState()
public
view
returns (uint256 support, uint256 execuitionQuorum, bool isExecuted)
Expand All @@ -45,10 +45,11 @@

/// @notice Executes the emergency activation if the quorum is reached
/// @dev Calls the emergencyActivate function on the Emergency Protected Timelock contract
function executeEmergencyActivate() external {
function executeActivateEmergencyMode() external {
_markUsed(EMERGENCY_ACTIVATION_HASH);
Address.functionCall(
EMERGENCY_PROTECTED_TIMELOCK, abi.encodeWithSelector(IEmergencyProtectedTimelock.emergencyActivate.selector)
EMERGENCY_PROTECTED_TIMELOCK,
abi.encodeWithSelector(IEmergencyProtectedTimelock.activateEmergencyMode.selector)
);
}
}
6 changes: 4 additions & 2 deletions contracts/committees/ResealCommittee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {HashConsensus} from "./HashConsensus.sol";
import {ProposalsList} from "./ProposalsList.sol";

interface IDualGovernance {
function reseal(address[] memory sealables) external;
function resealSealables(address[] memory sealables) external;
}

/// @title Reseal Committee Contract
Expand Down Expand Up @@ -59,7 +59,9 @@ contract ResealCommittee is HashConsensus, ProposalsList {
(, bytes32 key) = _encodeResealProposal(sealables);
_markUsed(key);

Address.functionCall(DUAL_GOVERNANCE, abi.encodeWithSelector(IDualGovernance.reseal.selector, sealables));
Address.functionCall(
DUAL_GOVERNANCE, abi.encodeWithSelector(IDualGovernance.resealSealables.selector, sealables)
);

bytes32 resealNonceHash = keccak256(abi.encode(sealables));
_resealNonces[resealNonceHash]++;
Expand Down
12 changes: 6 additions & 6 deletions docs/plan-b.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,27 +333,27 @@ Initializes the contract with an owner, committee members, a quorum, and the add
#### Preconditions
- `executionQuorum` MUST be greater than 0.

### Function: `EmergencyActivationCommittee.approveEmergencyActivate`
### Function: `EmergencyActivationCommittee.approveActivateEmergencyMode`
```solidity
function approveEmergencyActivate() public onlyMember
function approveActivateEmergencyMode() public onlyMember
```
Approves the emergency activation by voting on the `EMERGENCY_ACTIVATION_HASH`.

#### Preconditions
- MUST be called by a committee member.

### Function: `EmergencyActivationCommittee.getEmergencyActivateState`
### Function: `EmergencyActivationCommittee.getActivateEmergencyModeState`
```solidity
function getEmergencyActivateState()
function getActivateEmergencyModeState()
public
view
returns (uint256 support, uint256 executionQuorum, bool isExecuted)
```
Returns the state of the emergency activation proposal, including the support count, quorum, and execution status.

### Function: `EmergencyActivationCommittee.executeEmergencyActivate`
### Function: `EmergencyActivationCommittee.executeActivateEmergencyMode`
```solidity
function executeEmergencyActivate() external
function executeActivateEmergencyMode() external
```
Executes the emergency activation by calling the `emergencyActivate` function on the `EmergencyProtectedTimelock` contract.

Expand Down
12 changes: 6 additions & 6 deletions docs/specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -1326,10 +1326,10 @@ executionQuorum MUST be greater than 0.
emergencyProtectedTimelock MUST be a valid address.


### Function: EmergencyActivationCommittee.approveEmergencyActivate
### Function: EmergencyActivationCommittee.approveActivateEmergencyMode

```solidity
function approveEmergencyActivate() public onlyMember
function approveActivateEmergencyMode() public onlyMember
```

Approves the emergency activation by voting on the EMERGENCY_ACTIVATION_HASH.
Expand All @@ -1338,21 +1338,21 @@ Approves the emergency activation by voting on the EMERGENCY_ACTIVATION_HASH.

* MUST be called by a member.

### Function: EmergencyActivationCommittee.getEmergencyActivateState
### Function: EmergencyActivationCommittee.getActivateEmergencyModeState

```solidity
function getEmergencyActivateState()
function getActivateEmergencyModeState()
public
view
returns (uint256 support, uint256 executionQuorum, bool isExecuted)
```

Returns the state of the emergency activation proposal including support count, quorum, and execution status.

### Function: EmergencyActivationCommittee.executeEmergencyActivate
### Function: EmergencyActivationCommittee.executeActivateEmergencyMode

```solidity
function executeEmergencyActivate() external
function executeActivateEmergencyMode() external
```

Executes the emergency activation by calling the emergencyActivate function on the EmergencyProtectedTimelock contract.
Expand Down
77 changes: 77 additions & 0 deletions test/scenario/emergency-committee.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {
ScenarioTestBlueprint, percents, ExternalCall, ExternalCallHelpers
} from "../utils/scenario-test-blueprint.sol";

import {EmergencyProtectedTimelock} from "contracts/EmergencyProtectedTimelock.sol";

import {DAO_AGENT} from "../utils/mainnet-addresses.sol";

contract EmergencyCommitteeTest is ScenarioTestBlueprint {
address internal immutable _VETOER = makeAddr("VETOER");
uint256 public constant PAUSE_INFINITELY = type(uint256).max;

function setUp() external {
_selectFork();
_deployTarget();
_deployDualGovernanceSetup( /* isEmergencyProtectionEnabled */ true);
_depositStETH(_VETOER, 1 ether);
}

function test_emergency_committees_happy_path() external {
uint256 quorum;
uint256 support;
bool isExecuted;

address[] memory members;

ExternalCall[] memory proposalCalls = _getTargetRegularStaffCalls();
uint256 proposalIdToExecute = _submitProposal(_dualGovernance, "Proposal for execution", proposalCalls);

_wait(_config.AFTER_SUBMIT_DELAY().plusSeconds(1));
_assertCanSchedule(_dualGovernance, proposalIdToExecute, true);
_scheduleProposal(_dualGovernance, proposalIdToExecute);

// Emergency Activation
members = _emergencyActivationCommittee.getMembers();
for (uint256 i = 0; i < _emergencyActivationCommittee.quorum() - 1; i++) {
vm.prank(members[i]);
_emergencyActivationCommittee.approveActivateEmergencyMode();
(support, quorum, isExecuted) = _emergencyActivationCommittee.getActivateEmergencyModeState();
assert(support < quorum);
assert(isExecuted == false);
}

vm.prank(members[members.length - 1]);
_emergencyActivationCommittee.approveActivateEmergencyMode();
(support, quorum, isExecuted) = _emergencyActivationCommittee.getActivateEmergencyModeState();
assert(support == quorum);
assert(isExecuted == false);

_emergencyActivationCommittee.executeActivateEmergencyMode();
(support, quorum, isExecuted) = _emergencyActivationCommittee.getActivateEmergencyModeState();
assert(isExecuted == true);

// Emergency Execute
members = _emergencyExecutionCommittee.getMembers();
for (uint256 i = 0; i < _emergencyExecutionCommittee.quorum() - 1; i++) {
vm.prank(members[i]);
_emergencyExecutionCommittee.voteEmergencyExecute(proposalIdToExecute, true);
(support, quorum, isExecuted) = _emergencyExecutionCommittee.getEmergencyExecuteState(proposalIdToExecute);
assert(support < quorum);
assert(isExecuted == false);
}

vm.prank(members[members.length - 1]);
_emergencyExecutionCommittee.voteEmergencyExecute(proposalIdToExecute, true);
(support, quorum, isExecuted) = _emergencyExecutionCommittee.getEmergencyExecuteState(proposalIdToExecute);
assert(support == quorum);
assert(isExecuted == false);

_emergencyExecutionCommittee.executeEmergencyExecute(proposalIdToExecute);
(support, quorum, isExecuted) = _emergencyExecutionCommittee.getEmergencyExecuteState(proposalIdToExecute);
assert(isExecuted == true);
}
}
67 changes: 67 additions & 0 deletions test/scenario/reseal-committee.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {ScenarioTestBlueprint, ExternalCall, percents} from "../utils/scenario-test-blueprint.sol";
import {DualGovernance} from "../../contracts/DualGovernance.sol";
import {ResealManager} from "../../contracts/ResealManager.sol";
import {DAO_AGENT} from "../utils/mainnet-addresses.sol";

contract ResealCommitteeTest is ScenarioTestBlueprint {
address internal immutable _VETOER = makeAddr("VETOER");
uint256 public constant PAUSE_INFINITELY = type(uint256).max;

function setUp() external {
_selectFork();
_deployTarget();
_deployDualGovernanceSetup( /* isEmergencyProtectionEnabled */ true);
_depositStETH(_VETOER, 1 ether);
}

function test_reseal_committees_happy_path() external {
uint256 quorum;
uint256 support;
bool isExecuted;

address[] memory members;

address[] memory sealables = new address[](1);
sealables[0] = address(_WITHDRAWAL_QUEUE);

vm.prank(DAO_AGENT);
_WITHDRAWAL_QUEUE.grantRole(0x139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d, address(this));

// Reseal
members = _resealCommittee.getMembers();
for (uint256 i = 0; i < _resealCommittee.quorum() - 1; i++) {
vm.prank(members[i]);
_resealCommittee.voteReseal(sealables, true);
(support, quorum, isExecuted) = _resealCommittee.getResealState(sealables);
assert(support < quorum);
assert(isExecuted == false);
}

vm.prank(members[members.length - 1]);
_resealCommittee.voteReseal(sealables, true);
(support, quorum, isExecuted) = _resealCommittee.getResealState(sealables);
assert(support == quorum);
assert(isExecuted == false);

_assertNormalState();

vm.expectRevert(abi.encodeWithSelector(DualGovernance.ResealIsNotAllowedInNormalState.selector));
_resealCommittee.executeReseal(sealables);

_lockStETH(_VETOER, percents(_config.FIRST_SEAL_RAGE_QUIT_SUPPORT()));
_lockStETH(_VETOER, 1 gwei);
_assertVetoSignalingState();

assertEq(_WITHDRAWAL_QUEUE.isPaused(), false);
vm.expectRevert(abi.encodeWithSelector(ResealManager.SealableWrongPauseState.selector));
_resealCommittee.executeReseal(sealables);

_WITHDRAWAL_QUEUE.pauseFor(3600 * 24 * 6);
assertEq(_WITHDRAWAL_QUEUE.isPaused(), true);

_resealCommittee.executeReseal(sealables);
}
}
Loading