Skip to content

Commit

Permalink
Merge pull request #109 from lidofinance/develop
Browse files Browse the repository at this point in the history
1.1.0-alpha release
  • Loading branch information
Psirex authored Aug 28, 2024
2 parents dfaf963 + 64ea7a9 commit 30f0ebc
Show file tree
Hide file tree
Showing 41 changed files with 2,708 additions and 1,119 deletions.
19 changes: 19 additions & 0 deletions contracts/DualGovernance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ contract DualGovernance is IDualGovernance {
// Events
// ---

event CancelAllPendingProposalsSkipped();
event CancelAllPendingProposalsExecuted();
event EscrowMasterCopyDeployed(address escrowMasterCopy);
event ConfigProviderSet(IDualGovernanceConfigProvider newConfigProvider);

Expand Down Expand Up @@ -138,11 +140,27 @@ contract DualGovernance is IDualGovernance {
}

function cancelAllPendingProposals() external {
_stateMachine.activateNextState(_configProvider.getDualGovernanceConfig(), ESCROW_MASTER_COPY);

Proposers.Proposer memory proposer = _proposers.getProposer(msg.sender);
if (proposer.executor != TIMELOCK.getAdminExecutor()) {
revert NotAdminProposer();
}

State currentState = _stateMachine.getCurrentState();
if (currentState != State.VetoSignalling && currentState != State.VetoSignallingDeactivation) {
/// @dev Some proposer contracts, like Aragon Voting, may not support canceling decisions that have already
/// reached consensus. This could lead to a situation where a proposer’s cancelAllPendingProposals() call
/// becomes unexecutable if the Dual Governance state changes. However, it might become executable again if
/// the system state shifts back to VetoSignalling or VetoSignallingDeactivation.
/// To avoid such a scenario, an early return is used instead of a revert when proposals cannot be canceled
/// due to an unsuitable Dual Governance state.
emit CancelAllPendingProposalsSkipped();
return;
}

TIMELOCK.cancelAllNonExecutedProposals();
emit CancelAllPendingProposalsExecuted();
}

function canSubmitProposal() public view returns (bool) {
Expand Down Expand Up @@ -267,6 +285,7 @@ contract DualGovernance is IDualGovernance {

function tiebreakerScheduleProposal(uint256 proposalId) external {
_tiebreaker.checkCallerIsTiebreakerCommittee();
_stateMachine.activateNextState(_configProvider.getDualGovernanceConfig(), ESCROW_MASTER_COPY);
_tiebreaker.checkTie(_stateMachine.getCurrentState(), _stateMachine.getNormalOrVetoCooldownStateExitedAt());
TIMELOCK.schedule(proposalId);
}
Expand Down
41 changes: 30 additions & 11 deletions contracts/EmergencyProtectedTimelock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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.
Expand Down
34 changes: 24 additions & 10 deletions contracts/Escrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ contract Escrow is IEscrow {
error UnfinalizedUnstETHIds();
error NonProxyCallsForbidden();
error BatchesQueueIsNotClosed();
error EmptyUnstETHIds();
error InvalidBatchSize(uint256 size);
error CallerIsNotDualGovernance(address caller);
error InvalidHintsLength(uint256 actual, uint256 expected);
Expand Down Expand Up @@ -131,8 +132,8 @@ contract Escrow is IEscrow {
// ---

function lockStETH(uint256 amount) external returns (uint256 lockedStETHShares) {
_escrowState.checkSignallingEscrow();
DUAL_GOVERNANCE.activateNextState();
_escrowState.checkSignallingEscrow();

lockedStETHShares = ST_ETH.getSharesByPooledEth(amount);
_accounting.accountStETHSharesLock(msg.sender, SharesValues.from(lockedStETHShares));
Expand All @@ -142,10 +143,10 @@ contract Escrow is IEscrow {
}

function unlockStETH() external returns (uint256 unlockedStETHShares) {
_escrowState.checkSignallingEscrow();

DUAL_GOVERNANCE.activateNextState();
_escrowState.checkSignallingEscrow();
_accounting.checkMinAssetsLockDurationPassed(msg.sender, _escrowState.minAssetsLockDuration);

unlockedStETHShares = _accounting.accountStETHSharesUnlock(msg.sender).toUint256();
ST_ETH.transferShares(msg.sender, unlockedStETHShares);

Expand All @@ -157,8 +158,8 @@ contract Escrow is IEscrow {
// ---

function lockWstETH(uint256 amount) external returns (uint256 lockedStETHShares) {
_escrowState.checkSignallingEscrow();
DUAL_GOVERNANCE.activateNextState();
_escrowState.checkSignallingEscrow();

WST_ETH.transferFrom(msg.sender, address(this), amount);
lockedStETHShares = ST_ETH.getSharesByPooledEth(WST_ETH.unwrap(amount));
Expand All @@ -168,10 +169,10 @@ contract Escrow is IEscrow {
}

function unlockWstETH() external returns (uint256 unlockedStETHShares) {
_escrowState.checkSignallingEscrow();
DUAL_GOVERNANCE.activateNextState();

_escrowState.checkSignallingEscrow();
_accounting.checkMinAssetsLockDurationPassed(msg.sender, _escrowState.minAssetsLockDuration);

SharesValue wstETHUnlocked = _accounting.accountStETHSharesUnlock(msg.sender);
unlockedStETHShares = WST_ETH.wrap(ST_ETH.getPooledEthByShares(wstETHUnlocked.toUint256()));
WST_ETH.transfer(msg.sender, unlockedStETHShares);
Expand All @@ -183,8 +184,12 @@ contract Escrow is IEscrow {
// Lock & unlock unstETH
// ---
function lockUnstETH(uint256[] memory unstETHIds) external {
_escrowState.checkSignallingEscrow();
if (unstETHIds.length == 0) {
revert EmptyUnstETHIds();
}

DUAL_GOVERNANCE.activateNextState();
_escrowState.checkSignallingEscrow();

WithdrawalRequestStatus[] memory statuses = WITHDRAWAL_QUEUE.getWithdrawalStatus(unstETHIds);
_accounting.accountUnstETHLock(msg.sender, unstETHIds, statuses);
Expand All @@ -197,10 +202,10 @@ contract Escrow is IEscrow {
}

function unlockUnstETH(uint256[] memory unstETHIds) external {
_escrowState.checkSignallingEscrow();
DUAL_GOVERNANCE.activateNextState();

_escrowState.checkSignallingEscrow();
_accounting.checkMinAssetsLockDurationPassed(msg.sender, _escrowState.minAssetsLockDuration);

_accounting.accountUnstETHUnlock(msg.sender, unstETHIds);
uint256 unstETHIdsCount = unstETHIds.length;
for (uint256 i = 0; i < unstETHIdsCount; ++i) {
Expand Down Expand Up @@ -271,6 +276,12 @@ contract Escrow is IEscrow {
});

_batchesQueue.addUnstETHIds(WITHDRAWAL_QUEUE.requestWithdrawals(requestAmounts, address(this)));

stETHRemaining = ST_ETH.balanceOf(address(this));

if (stETHRemaining < minStETHWithdrawalRequestAmount) {
_batchesQueue.close();
}
}

// ---
Expand Down Expand Up @@ -364,6 +375,9 @@ contract Escrow is IEscrow {
}

function withdrawETH(uint256[] calldata unstETHIds) external {
if (unstETHIds.length == 0) {
revert EmptyUnstETHIds();
}
_escrowState.checkRageQuitEscrow();
_escrowState.checkWithdrawalsTimelockPassed();
ETHValue ethToWithdraw = _accounting.accountUnstETHWithdraw(msg.sender, unstETHIds);
Expand All @@ -389,7 +403,7 @@ contract Escrow is IEscrow {

state.unstETHIdsCount = assets.unstETHIds.length;
state.stETHLockedShares = assets.stETHLockedShares.toUint256();
state.unstETHLockedShares = assets.stETHLockedShares.toUint256();
state.unstETHLockedShares = assets.unstETHLockedShares.toUint256();
state.lastAssetsLockTimestamp = assets.lastAssetsLockTimestamp.toSeconds();
}

Expand Down
9 changes: 6 additions & 3 deletions contracts/committees/EmergencyActivationCommittee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol";

import {HashConsensus} from "./HashConsensus.sol";
import {ITimelock} from "../interfaces/ITimelock.sol";
import {Duration, Durations} from "../types/Duration.sol";
import {Timestamp} from "../types/Timestamp.sol";

/// @title Emergency Activation Committee Contract
/// @notice This contract allows a committee to approve and execute an emergency activation
Expand All @@ -19,7 +21,7 @@ contract EmergencyActivationCommittee is HashConsensus {
address[] memory committeeMembers,
uint256 executionQuorum,
address emergencyProtectedTimelock
) HashConsensus(owner, 0) {
) HashConsensus(owner, Durations.from(0)) {
EMERGENCY_PROTECTED_TIMELOCK = emergencyProtectedTimelock;

_addMembers(committeeMembers, executionQuorum);
Expand All @@ -34,12 +36,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, Timestamp quorumAt, bool isExecuted)
{
return _getHashState(EMERGENCY_ACTIVATION_HASH);
}
Expand Down
16 changes: 10 additions & 6 deletions contracts/committees/EmergencyExecutionCommittee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {HashConsensus} from "./HashConsensus.sol";
import {ProposalsList} from "./ProposalsList.sol";
import {ITimelock} from "../interfaces/ITimelock.sol";
import {Timestamp} from "../types/Timestamp.sol";
import {Durations} from "../types/Duration.sol";

enum ProposalType {
EmergencyExecute,
Expand All @@ -22,7 +24,7 @@ contract EmergencyExecutionCommittee is HashConsensus, ProposalsList {
address[] memory committeeMembers,
uint256 executionQuorum,
address emergencyProtectedTimelock
) HashConsensus(owner, 0) {
) HashConsensus(owner, Durations.from(0)) {
EMERGENCY_PROTECTED_TIMELOCK = emergencyProtectedTimelock;

_addMembers(committeeMembers, executionQuorum);
Expand All @@ -46,12 +48,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, Timestamp quorumAt, bool isExecuted)
{
(, bytes32 key) = _encodeEmergencyExecute(proposalId);
return _getHashState(key);
Expand Down Expand Up @@ -93,14 +96,15 @@ contract EmergencyExecutionCommittee is HashConsensus, ProposalsList {
_pushProposal(proposalKey, uint256(ProposalType.EmergencyReset), bytes(""));
}

/// @notice Gets the current state of an emergency reset opprosal
/// @notice Gets the current state of an emergency reset 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 getEmergencyResetState()
public
view
returns (uint256 support, uint256 execuitionQuorum, bool isExecuted)
returns (uint256 support, uint256 executionQuorum, Timestamp quorumAt, bool isExecuted)
{
bytes32 proposalKey = _encodeEmergencyResetProposalKey();
return _getHashState(proposalKey);
Expand Down
Loading

0 comments on commit 30f0ebc

Please sign in to comment.