Skip to content

Commit

Permalink
Merge pull request #41 from lidofinance/feat/emergency-protected-time…
Browse files Browse the repository at this point in the history
…lock-unit-tests

EmergencyProtectedTimelock & SingleGovernance unit tests
  • Loading branch information
Psirex authored Jun 20, 2024
2 parents 74327cf + 37388fa commit 683f152
Show file tree
Hide file tree
Showing 12 changed files with 1,862 additions and 33 deletions.
4 changes: 0 additions & 4 deletions contracts/EmergencyProtectedTimelock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ contract EmergencyProtectedTimelock is ConfigurationProvider {

error InvalidGovernance(address governance);
error NotGovernance(address account, address governance);
error SchedulingDisabled();
error UnscheduledExecutionForbidden();

event GovernanceSet(address governance);
event ProposalLaunched(address indexed proposer, address indexed executor, uint256 indexed proposalId);

address internal _governance;

Expand All @@ -30,7 +27,6 @@ contract EmergencyProtectedTimelock is ConfigurationProvider {
function submit(address executor, ExecutorCall[] calldata calls) external returns (uint256 newProposalId) {
_checkGovernance(msg.sender);
newProposalId = _proposals.submit(executor, calls);
emit ProposalLaunched(msg.sender, executor, newProposalId);
}

function schedule(uint256 proposalId) external returns (uint256 submittedAt) {
Expand Down
4 changes: 4 additions & 0 deletions contracts/SingleGovernance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ contract SingleGovernance is IGovernance, ConfigurationProvider {
TIMELOCK.schedule(proposalId);
}

function executeProposal(uint256 proposalId) external {
TIMELOCK.execute(proposalId);
}

function canSchedule(uint256 proposalId) external view returns (bool) {
return TIMELOCK.canSchedule(proposalId);
}
Expand Down
14 changes: 6 additions & 8 deletions contracts/libraries/EmergencyProtection.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ struct EmergencyState {
library EmergencyProtection {
error NotEmergencyActivator(address account);
error NotEmergencyEnactor(address account);
error EmergencyPeriodFinished();
error EmergencyCommitteeExpired();
error EmergencyCommitteeExpired(uint256 timestamp, uint256 protectedTill);
error InvalidEmergencyModeActiveValue(bool actual, bool expected);

event EmergencyModeActivated();
event EmergencyModeDeactivated();
event EmergencyGovernanceReset();
event EmergencyModeActivated(uint256 timestamp);
event EmergencyModeDeactivated(uint256 timestamp);
event EmergencyActivationCommitteeSet(address indexed activationCommittee);
event EmergencyExecutionCommitteeSet(address indexed executionCommittee);
event EmergencyModeDurationSet(uint256 emergencyModeDuration);
Expand Down Expand Up @@ -74,10 +72,10 @@ library EmergencyProtection {

function activate(State storage self) internal {
if (block.timestamp > self.protectedTill) {
revert EmergencyCommitteeExpired();
revert EmergencyCommitteeExpired(block.timestamp, self.protectedTill);
}
self.emergencyModeEndsAfter = SafeCast.toUint40(block.timestamp + self.emergencyModeDuration);
emit EmergencyModeActivated();
emit EmergencyModeActivated(block.timestamp);
}

function deactivate(State storage self) internal {
Expand All @@ -86,7 +84,7 @@ library EmergencyProtection {
self.protectedTill = 0;
self.emergencyModeDuration = 0;
self.emergencyModeEndsAfter = 0;
emit EmergencyModeDeactivated();
emit EmergencyModeDeactivated(block.timestamp);
}

function getEmergencyState(State storage self) internal view returns (EmergencyState memory res) {
Expand Down
26 changes: 13 additions & 13 deletions contracts/libraries/Proposals.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ enum Status {
Submitted,
Scheduled,
Executed,
Canceled
Cancelled
}

struct Proposal {
Expand All @@ -34,12 +34,12 @@ library Proposals {

struct State {
// any proposals with ids less or equal to the given one cannot be executed
uint256 lastCanceledProposalId;
uint256 lastCancelledProposalId;
ProposalPacked[] proposals;
}

error EmptyCalls();
error ProposalCanceled(uint256 proposalId);
error ProposalCancelled(uint256 proposalId);
error ProposalNotFound(uint256 proposalId);
error ProposalNotScheduled(uint256 proposalId);
error ProposalNotSubmitted(uint256 proposalId);
Expand All @@ -49,15 +49,15 @@ library Proposals {
event ProposalScheduled(uint256 indexed id);
event ProposalSubmitted(uint256 indexed id, address indexed executor, ExecutorCall[] calls);
event ProposalExecuted(uint256 indexed id, bytes[] callResults);
event ProposalsCanceledTill(uint256 proposalId);
event ProposalsCancelledTill(uint256 proposalId);

// The id of the first proposal
uint256 private constant PROPOSAL_ID_OFFSET = 1;

function submit(
State storage self,
address executor,
ExecutorCall[] calldata calls
ExecutorCall[] memory calls
) internal returns (uint256 newProposalId) {
if (calls.length == 0) {
revert EmptyCalls();
Expand All @@ -67,9 +67,8 @@ library Proposals {

self.proposals.push();
ProposalPacked storage newProposal = self.proposals[newProposalIndex];
newProposal.executor = executor;

newProposal.executedAt = 0;
newProposal.executor = executor;
newProposal.submittedAt = TimeUtils.timestamp();

// copying of arrays of custom types from calldata to storage has not been supported by the
Expand Down Expand Up @@ -105,8 +104,8 @@ library Proposals {

function cancelAll(State storage self) internal {
uint256 lastProposalId = self.proposals.length;
self.lastCanceledProposalId = lastProposalId;
emit ProposalsCanceledTill(lastProposalId);
self.lastCancelledProposalId = lastProposalId;
emit ProposalsCancelledTill(lastProposalId);
}

function get(State storage self, uint256 proposalId) internal view returns (Proposal memory proposal) {
Expand All @@ -117,6 +116,7 @@ library Proposals {
proposal.status = _getProposalStatus(self, proposalId);
proposal.executor = packed.executor;
proposal.submittedAt = packed.submittedAt;
proposal.scheduledAt = packed.scheduledAt;
proposal.executedAt = packed.executedAt;
proposal.calls = packed.calls;
}
Expand All @@ -143,7 +143,7 @@ library Proposals {
&& block.timestamp >= _packed(self, proposalId).submittedAt + afterSubmitDelay;
}

function _executeProposal(State storage self, uint256 proposalId) private returns (bytes[] memory results) {
function _executeProposal(State storage self, uint256 proposalId) private {
ProposalPacked storage packed = _packed(self, proposalId);
packed.executedAt = TimeUtils.timestamp();

Expand All @@ -153,7 +153,7 @@ library Proposals {
assert(callsCount > 0);

address executor = packed.executor;
results = new bytes[](callsCount);
bytes[] memory results = new bytes[](callsCount);
for (uint256 i = 0; i < callsCount; ++i) {
results[i] = IExecutor(payable(executor)).execute(calls[i].target, calls[i].value, calls[i].payload);
}
Expand Down Expand Up @@ -204,13 +204,13 @@ library Proposals {
}
}

function _getProposalStatus(State storage self, uint256 proposalId) private view returns (Status) {
function _getProposalStatus(State storage self, uint256 proposalId) private view returns (Status status) {
if (proposalId < PROPOSAL_ID_OFFSET || proposalId > self.proposals.length) return Status.NotExist;

ProposalPacked storage packed = _packed(self, proposalId);

if (packed.executedAt != 0) return Status.Executed;
if (proposalId <= self.lastCanceledProposalId) return Status.Canceled;
if (proposalId <= self.lastCancelledProposalId) return Status.Cancelled;
if (packed.scheduledAt != 0) return Status.Scheduled;
if (packed.submittedAt != 0) return Status.Submitted;
assert(false);
Expand Down
Loading

0 comments on commit 683f152

Please sign in to comment.