Skip to content

Commit

Permalink
Update quorumAt after execution quorum changing
Browse files Browse the repository at this point in the history
  • Loading branch information
bulbozaur committed Aug 14, 2024
1 parent 5cedbd4 commit 1a17265
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 51 deletions.
5 changes: 3 additions & 2 deletions contracts/committees/EmergencyActivationCommittee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ contract EmergencyActivationCommittee is HashConsensus {

/// @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 executionQuorum The required number of votes for execution
/// @return quorumAt The timestamp when the quorum was reached
/// @return isExecuted Whether the activation has been executed
function getActivateEmergencyModeState()
public
view
returns (uint256 support, uint256 execuitionQuorum, bool isExecuted)
returns (uint256 support, uint256 executionQuorum, uint256 quorumAt, bool isExecuted)
{
return _getHashState(EMERGENCY_ACTIVATION_HASH);
}
Expand Down
10 changes: 6 additions & 4 deletions contracts/committees/EmergencyExecutionCommittee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ contract EmergencyExecutionCommittee is HashConsensus, ProposalsList {
/// @notice Gets the current state of an emergency execution proposal
/// @param proposalId The ID of the proposal
/// @return support The number of votes in support of the proposal
/// @return execuitionQuorum The required number of votes for execution
/// @return executionQuorum The required number of votes for execution
/// @return quorumAt The timestamp when the quorum was reached
/// @return isExecuted Whether the proposal has been executed
function getEmergencyExecuteState(uint256 proposalId)
public
view
returns (uint256 support, uint256 execuitionQuorum, bool isExecuted)
returns (uint256 support, uint256 executionQuorum, uint256 quorumAt, bool isExecuted)
{
(, bytes32 key) = _encodeEmergencyExecute(proposalId);
return _getHashState(key);
Expand Down Expand Up @@ -95,12 +96,13 @@ contract EmergencyExecutionCommittee is HashConsensus, ProposalsList {

/// @notice Gets the current state of an emergency reset opprosal
/// @return support The number of votes in support of the proposal
/// @return execuitionQuorum The required number of votes for execution
/// @return executionQuorum The required number of votes for execution
/// @return quorumAt The timestamp when the quorum was reached
/// @return isExecuted Whether the proposal has been executed
function getEmergencyResetState()
public
view
returns (uint256 support, uint256 execuitionQuorum, bool isExecuted)
returns (uint256 support, uint256 executionQuorum, uint256 quorumAt, bool isExecuted)
{
bytes32 proposalKey = _encodeEmergencyResetProposalKey();
return _getHashState(proposalKey);
Expand Down
22 changes: 19 additions & 3 deletions contracts/committees/HashConsensus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,17 @@ abstract contract HashConsensus is Ownable {
/// @dev Internal function to retrieve the state of a hash
/// @param hash The hash to get the state for
/// @return support The number of votes in support of the hash
/// @return execuitionQuorum The required number of votes for execution
/// @return executionQuorum The required number of votes for execution
/// @return quorumAt The timestamp when the quorum was reached
/// @return isUsed Whether the hash has been used
function _getHashState(bytes32 hash)
internal
view
returns (uint256 support, uint256 execuitionQuorum, bool isUsed)
returns (uint256 support, uint256 executionQuorum, uint256 quorumAt, bool isUsed)
{
support = _getSupport(hash);
execuitionQuorum = quorum;
executionQuorum = quorum;
quorumAt = _hashStates[hash].quorumAt;
isUsed = _hashStates[hash].usedAt > 0;
}

Expand Down Expand Up @@ -167,6 +169,20 @@ abstract contract HashConsensus is Ownable {
_setQuorum(newQuorum);
}

/// @notice Updates the quorum for a given hash if the quorum is reached and not set
/// and the hash has not been used
/// @param hash The hash to update the quorum for
function updateQuorum(bytes32 hash) public {
if (_hashStates[hash].usedAt > 0) {
revert HashAlreadyUsed(hash);
}

uint256 support = _getSupport(hash);
if (support >= quorum && _hashStates[hash].quorumAt == 0) {
_hashStates[hash].quorumAt = uint40(block.timestamp);
}
}

/// @notice Sets the execution quorum required for certain operations.
/// @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.
Expand Down
5 changes: 3 additions & 2 deletions contracts/committees/ResealCommittee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ contract ResealCommittee is HashConsensus, ProposalsList {
/// @dev Retrieves the state of the reseal proposal for a sealed address
/// @param sealable The addresses for the reseal proposal
/// @return support The number of votes in support of the proposal
/// @return execuitionQuorum The required number of votes for execution
/// @return executionQuorum The required number of votes for execution
/// @return quorumAt The timestamp when the quorum was reached
/// @return isExecuted Whether the proposal has been executed
function getResealState(address sealable)
public
view
returns (uint256 support, uint256 execuitionQuorum, bool isExecuted)
returns (uint256 support, uint256 executionQuorum, uint256 quorumAt, bool isExecuted)
{
(, bytes32 key) = _encodeResealProposal(sealable);
return _getHashState(key);
Expand Down
10 changes: 6 additions & 4 deletions contracts/committees/TiebreakerCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ contract TiebreakerCore is ITiebreakerCore, HashConsensus, ProposalsList {
/// @dev Retrieves the state of the schedule proposal for a given proposal ID
/// @param proposalId The ID of the proposal
/// @return support The number of votes in support of the proposal
/// @return execuitionQuorum The required number of votes for execution
/// @return executionQuorum The required number of votes for execution
/// @return quorumAt The timestamp when the quorum was reached
/// @return isExecuted Whether the proposal has been executed
function getScheduleProposalState(uint256 proposalId)
public
view
returns (uint256 support, uint256 execuitionQuorum, bool isExecuted)
returns (uint256 support, uint256 executionQuorum, uint256 quorumAt, bool isExecuted)
{
(, bytes32 key) = _encodeScheduleProposal(proposalId);
return _getHashState(key);
Expand Down Expand Up @@ -104,12 +105,13 @@ contract TiebreakerCore is ITiebreakerCore, HashConsensus, ProposalsList {
/// @param sealable The address to resume
/// @param nonce The nonce for the resume proposal
/// @return support The number of votes in support of the proposal
/// @return execuitionQuorum The required number of votes for execution
/// @return executionQuorum The required number of votes for execution
/// @return quorumAt The timestamp when the quorum was reached
/// @return isExecuted Whether the proposal has been executed
function getSealableResumeState(
address sealable,
uint256 nonce
) public view returns (uint256 support, uint256 execuitionQuorum, bool isExecuted) {
) public view returns (uint256 support, uint256 executionQuorum, uint256 quorumAt, bool isExecuted) {
(, bytes32 key) = _encodeSealableResume(sealable, nonce);
return _getHashState(key);
}
Expand Down
10 changes: 6 additions & 4 deletions contracts/committees/TiebreakerSubCommittee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ contract TiebreakerSubCommittee is HashConsensus, ProposalsList {
/// @dev Retrieves the state of the schedule proposal for a given proposal ID
/// @param proposalId The ID of the proposal
/// @return support The number of votes in support of the proposal
/// @return execuitionQuorum The required number of votes for execution
/// @return executionQuorum The required number of votes for execution
/// @return quorumAt The number of votes required to reach quorum
/// @return isExecuted Whether the proposal has been executed
function getScheduleProposalState(uint256 proposalId)
public
view
returns (uint256 support, uint256 execuitionQuorum, bool isExecuted)
returns (uint256 support, uint256 executionQuorum, uint256 quorumAt, bool isExecuted)
{
(, bytes32 key) = _encodeAproveProposal(proposalId);
return _getHashState(key);
Expand Down Expand Up @@ -96,12 +97,13 @@ contract TiebreakerSubCommittee is HashConsensus, ProposalsList {
/// @dev Retrieves the state of the resume sealable proposal for a given address
/// @param sealable The address to resume
/// @return support The number of votes in support of the proposal
/// @return execuitionQuorum The required number of votes for execution
/// @return executionQuorum The required number of votes for execution
/// @return quorumAt The timestamp when the quorum was reached
/// @return isExecuted Whether the proposal has been executed
function getSealableResumeState(address sealable)
public
view
returns (uint256 support, uint256 execuitionQuorum, bool isExecuted)
returns (uint256 support, uint256 executionQuorum, uint256 quorumAt, bool isExecuted)
{
(, bytes32 key,) = _encodeSealableResume(sealable);
return _getHashState(key);
Expand Down
12 changes: 6 additions & 6 deletions test/scenario/emergency-committee.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,39 +39,39 @@ contract EmergencyCommitteeTest is ScenarioTestBlueprint {
for (uint256 i = 0; i < _emergencyActivationCommittee.quorum() - 1; i++) {
vm.prank(members[i]);
_emergencyActivationCommittee.approveActivateEmergencyMode();
(support, quorum, isExecuted) = _emergencyActivationCommittee.getActivateEmergencyModeState();
(support, quorum,, isExecuted) = _emergencyActivationCommittee.getActivateEmergencyModeState();
assert(support < quorum);
assert(isExecuted == false);
}

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

_emergencyActivationCommittee.executeActivateEmergencyMode();
(support, quorum, isExecuted) = _emergencyActivationCommittee.getActivateEmergencyModeState();
(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);
(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);
(support, quorum,, isExecuted) = _emergencyExecutionCommittee.getEmergencyExecuteState(proposalIdToExecute);
assert(support == quorum);
assert(isExecuted == false);

_emergencyExecutionCommittee.executeEmergencyExecute(proposalIdToExecute);
(support, quorum, isExecuted) = _emergencyExecutionCommittee.getEmergencyExecuteState(proposalIdToExecute);
(support, quorum,, isExecuted) = _emergencyExecutionCommittee.getEmergencyExecuteState(proposalIdToExecute);
assert(isExecuted == true);
}
}
4 changes: 2 additions & 2 deletions test/scenario/reseal-committee.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ contract ResealCommitteeTest is ScenarioTestBlueprint {
for (uint256 i = 0; i < _resealCommittee.quorum() - 1; i++) {
vm.prank(members[i]);
_resealCommittee.voteReseal(sealable, true);
(support, quorum, isExecuted) = _resealCommittee.getResealState(sealable);
(support, quorum,, isExecuted) = _resealCommittee.getResealState(sealable);
assert(support < quorum);
assert(isExecuted == false);
}

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

Expand Down
24 changes: 12 additions & 12 deletions test/scenario/tiebreaker.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,40 +42,40 @@ contract TiebreakerScenarioTest is ScenarioTestBlueprint {
for (uint256 i = 0; i < _tiebreakerSubCommittees[0].quorum() - 1; i++) {
vm.prank(members[i]);
_tiebreakerSubCommittees[0].scheduleProposal(proposalIdToExecute);
(support, quorum, isExecuted) = _tiebreakerSubCommittees[0].getScheduleProposalState(proposalIdToExecute);
(support, quorum,, isExecuted) = _tiebreakerSubCommittees[0].getScheduleProposalState(proposalIdToExecute);
assertTrue(support < quorum);
assertFalse(isExecuted);
}

vm.prank(members[members.length - 1]);
_tiebreakerSubCommittees[0].scheduleProposal(proposalIdToExecute);
(support, quorum, isExecuted) = _tiebreakerSubCommittees[0].getScheduleProposalState(proposalIdToExecute);
(support, quorum,, isExecuted) = _tiebreakerSubCommittees[0].getScheduleProposalState(proposalIdToExecute);
assertEq(support, quorum);
assertFalse(isExecuted);

_tiebreakerSubCommittees[0].executeScheduleProposal(proposalIdToExecute);
(support, quorum, isExecuted) = _tiebreakerCoreCommittee.getScheduleProposalState(proposalIdToExecute);
(support, quorum,, isExecuted) = _tiebreakerCoreCommittee.getScheduleProposalState(proposalIdToExecute);
assertTrue(support < quorum);

// Tiebreaker subcommittee 1
members = _tiebreakerSubCommittees[1].getMembers();
for (uint256 i = 0; i < _tiebreakerSubCommittees[1].quorum() - 1; i++) {
vm.prank(members[i]);
_tiebreakerSubCommittees[1].scheduleProposal(proposalIdToExecute);
(support, quorum, isExecuted) = _tiebreakerSubCommittees[1].getScheduleProposalState(proposalIdToExecute);
(support, quorum,, isExecuted) = _tiebreakerSubCommittees[1].getScheduleProposalState(proposalIdToExecute);
assertTrue(support < quorum);
assertEq(isExecuted, false);
}

vm.prank(members[members.length - 1]);
_tiebreakerSubCommittees[1].scheduleProposal(proposalIdToExecute);
(support, quorum, isExecuted) = _tiebreakerSubCommittees[1].getScheduleProposalState(proposalIdToExecute);
(support, quorum,, isExecuted) = _tiebreakerSubCommittees[1].getScheduleProposalState(proposalIdToExecute);
assertEq(support, quorum);
assertFalse(isExecuted);

// Approve proposal for scheduling
_tiebreakerSubCommittees[1].executeScheduleProposal(proposalIdToExecute);
(support, quorum, isExecuted) = _tiebreakerCoreCommittee.getScheduleProposalState(proposalIdToExecute);
(support, quorum,, isExecuted) = _tiebreakerCoreCommittee.getScheduleProposalState(proposalIdToExecute);
assertEq(support, quorum);

// Waiting for submit delay pass
Expand Down Expand Up @@ -114,21 +114,21 @@ contract TiebreakerScenarioTest is ScenarioTestBlueprint {
for (uint256 i = 0; i < _tiebreakerSubCommittees[0].quorum() - 1; i++) {
vm.prank(members[i]);
_tiebreakerSubCommittees[0].sealableResume(address(_lido.withdrawalQueue));
(support, quorum, isExecuted) =
(support, quorum,, isExecuted) =
_tiebreakerSubCommittees[0].getSealableResumeState(address(_lido.withdrawalQueue));
assertTrue(support < quorum);
assertFalse(isExecuted);
}

vm.prank(members[members.length - 1]);
_tiebreakerSubCommittees[0].sealableResume(address(_lido.withdrawalQueue));
(support, quorum, isExecuted) =
(support, quorum,, isExecuted) =
_tiebreakerSubCommittees[0].getSealableResumeState(address(_lido.withdrawalQueue));
assertEq(support, quorum);
assertFalse(isExecuted);

_tiebreakerSubCommittees[0].executeSealableResume(address(_lido.withdrawalQueue));
(support, quorum, isExecuted) = _tiebreakerCoreCommittee.getSealableResumeState(
(support, quorum,, isExecuted) = _tiebreakerCoreCommittee.getSealableResumeState(
address(_lido.withdrawalQueue),
_tiebreakerCoreCommittee.getSealableResumeNonce(address(_lido.withdrawalQueue))
);
Expand All @@ -139,21 +139,21 @@ contract TiebreakerScenarioTest is ScenarioTestBlueprint {
for (uint256 i = 0; i < _tiebreakerSubCommittees[1].quorum() - 1; i++) {
vm.prank(members[i]);
_tiebreakerSubCommittees[1].sealableResume(address(_lido.withdrawalQueue));
(support, quorum, isExecuted) =
(support, quorum,, isExecuted) =
_tiebreakerSubCommittees[1].getSealableResumeState(address(_lido.withdrawalQueue));
assertTrue(support < quorum);
assertEq(isExecuted, false);
}

vm.prank(members[members.length - 1]);
_tiebreakerSubCommittees[1].sealableResume(address(_lido.withdrawalQueue));
(support, quorum, isExecuted) =
(support, quorum,, isExecuted) =
_tiebreakerSubCommittees[1].getSealableResumeState(address(_lido.withdrawalQueue));
assertEq(support, quorum);
assertFalse(isExecuted);

_tiebreakerSubCommittees[1].executeSealableResume(address(_lido.withdrawalQueue));
(support, quorum, isExecuted) = _tiebreakerCoreCommittee.getSealableResumeState(
(support, quorum,, isExecuted) = _tiebreakerCoreCommittee.getSealableResumeState(
address(_lido.withdrawalQueue),
_tiebreakerCoreCommittee.getSealableResumeNonce(address(_lido.withdrawalQueue))
);
Expand Down
Loading

0 comments on commit 1a17265

Please sign in to comment.