Skip to content

Commit

Permalink
Merge pull request #225 from lidofinance/develop
Browse files Browse the repository at this point in the history
1.0.0-beta release
  • Loading branch information
bulbozaur authored Nov 29, 2024
2 parents 30f0ebc + 7ca533f commit e99d4fc
Show file tree
Hide file tree
Showing 95 changed files with 10,935 additions and 2,713 deletions.
358 changes: 264 additions & 94 deletions contracts/DualGovernance.sol

Large diffs are not rendered by default.

76 changes: 0 additions & 76 deletions contracts/DualGovernanceConfigProvider.sol

This file was deleted.

260 changes: 177 additions & 83 deletions contracts/EmergencyProtectedTimelock.sol

Large diffs are not rendered by default.

301 changes: 219 additions & 82 deletions contracts/Escrow.sol

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions contracts/Executor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

import {IExternalExecutor} from "./interfaces/IExternalExecutor.sol";

/// @title Executor
/// @notice Allows the contract owner to execute external function calls on specified target contracts with
/// possible value transfers.
contract Executor is IExternalExecutor, Ownable {
constructor(address owner) Ownable(owner) {}

/// @notice Allows the contract owner to execute external function calls on target contracts, optionally transferring ether.
/// @param target The address of the target contract on which to execute the function call.
/// @param value The amount of ether (in wei) to send with the function call.
/// @param payload The calldata for the function call.
/// @return result The data returned from the function call.
function execute(
address target,
uint256 value,
Expand All @@ -18,5 +26,6 @@ contract Executor is IExternalExecutor, Ownable {
result = Address.functionCallWithValue(target, payload, value);
}

/// @notice Allows the contract to receive ether.
receive() external payable {}
}
114 changes: 114 additions & 0 deletions contracts/ImmutableDualGovernanceConfigProvider.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {Duration} from "./types/Duration.sol";
import {PercentD16} from "./types/PercentD16.sol";

import {IDualGovernanceConfigProvider} from "./interfaces/IDualGovernanceConfigProvider.sol";

import {DualGovernanceConfig} from "./libraries/DualGovernanceConfig.sol";

/// @title Immutable Dual Governance Config Provider
/// @notice Provides configuration values for the Dual Governance system in a gas-efficient way using immutable
/// variables to store values.
contract ImmutableDualGovernanceConfigProvider is IDualGovernanceConfigProvider {
using DualGovernanceConfig for DualGovernanceConfig.Context;

// ---
// Immutable Variables
// ---

/// @notice The percentage of the total stETH supply that must be exceeded in the Signalling Escrow to transition
/// Dual Governance from the Normal state to the VetoSignalling state.
PercentD16 public immutable FIRST_SEAL_RAGE_QUIT_SUPPORT;

/// @notice The percentage of the total stETH supply that must be exceeded in the Signalling Escrow to transition
/// Dual Governance into the RageQuit state.
PercentD16 public immutable SECOND_SEAL_RAGE_QUIT_SUPPORT;

/// @notice The minimum duration that assets must remain locked in the Signalling Escrow contract before unlocking
/// is permitted.
Duration public immutable MIN_ASSETS_LOCK_DURATION;

/// @notice The minimum duration of the VetoSignalling state.
Duration public immutable VETO_SIGNALLING_MIN_DURATION;

/// @notice The maximum duration of the VetoSignalling state.
Duration public immutable VETO_SIGNALLING_MAX_DURATION;

/// @notice The minimum duration of the VetoSignalling state before it can be exited. Once in the VetoSignalling
/// state, it cannot be exited sooner than `vetoSignallingMinActiveDuration`.
Duration public immutable VETO_SIGNALLING_MIN_ACTIVE_DURATION;

/// @notice The maximum duration of the VetoSignallingDeactivation state.
Duration public immutable VETO_SIGNALLING_DEACTIVATION_MAX_DURATION;

/// @notice The duration of the VetoCooldown state.
Duration public immutable VETO_COOLDOWN_DURATION;

/// @notice The duration of the Rage Quit Extension Period.
Duration public immutable RAGE_QUIT_EXTENSION_PERIOD_DURATION;

/// @notice The minimum delay for ETH withdrawals after the Rage Quit process completes.
Duration public immutable RAGE_QUIT_ETH_WITHDRAWALS_MIN_DELAY;

/// @notice The maximum delay for ETH withdrawals after the Rage Quit process completes.
Duration public immutable RAGE_QUIT_ETH_WITHDRAWALS_MAX_DELAY;

/// @notice The incremental growth of the ETH withdrawal delay with each "continuous" Rage Quit (a Rage Quit is
/// considered continuous if, between two Rage Quits, Dual Governance has not re-entered
/// the Normal state).
Duration public immutable RAGE_QUIT_ETH_WITHDRAWALS_DELAY_GROWTH;

// ---
// Constructor
// ---

/// @notice Initializes the Dual Governance Configuration Provider with parameters, validating that key configuration
/// values are within logical ranges to prevent malfunction of the Dual Governance system.
/// @param dualGovernanceConfig The configuration struct containing all governance parameters.
constructor(DualGovernanceConfig.Context memory dualGovernanceConfig) {
dualGovernanceConfig.validate();

FIRST_SEAL_RAGE_QUIT_SUPPORT = dualGovernanceConfig.firstSealRageQuitSupport;
SECOND_SEAL_RAGE_QUIT_SUPPORT = dualGovernanceConfig.secondSealRageQuitSupport;

MIN_ASSETS_LOCK_DURATION = dualGovernanceConfig.minAssetsLockDuration;
VETO_SIGNALLING_MIN_DURATION = dualGovernanceConfig.vetoSignallingMinDuration;
VETO_SIGNALLING_MAX_DURATION = dualGovernanceConfig.vetoSignallingMaxDuration;

VETO_SIGNALLING_MIN_ACTIVE_DURATION = dualGovernanceConfig.vetoSignallingMinActiveDuration;
VETO_SIGNALLING_DEACTIVATION_MAX_DURATION = dualGovernanceConfig.vetoSignallingDeactivationMaxDuration;

VETO_COOLDOWN_DURATION = dualGovernanceConfig.vetoCooldownDuration;

RAGE_QUIT_EXTENSION_PERIOD_DURATION = dualGovernanceConfig.rageQuitExtensionPeriodDuration;
RAGE_QUIT_ETH_WITHDRAWALS_MIN_DELAY = dualGovernanceConfig.rageQuitEthWithdrawalsMinDelay;
RAGE_QUIT_ETH_WITHDRAWALS_MAX_DELAY = dualGovernanceConfig.rageQuitEthWithdrawalsMaxDelay;
RAGE_QUIT_ETH_WITHDRAWALS_DELAY_GROWTH = dualGovernanceConfig.rageQuitEthWithdrawalsDelayGrowth;
}

// ---
// Getters
// ---

/// @notice Returns the entire configuration for the Dual Governance system.
/// @return config A `DualGovernanceConfig.Context` struct containing all governance parameters.
function getDualGovernanceConfig() external view returns (DualGovernanceConfig.Context memory config) {
config.firstSealRageQuitSupport = FIRST_SEAL_RAGE_QUIT_SUPPORT;
config.secondSealRageQuitSupport = SECOND_SEAL_RAGE_QUIT_SUPPORT;

config.minAssetsLockDuration = MIN_ASSETS_LOCK_DURATION;
config.vetoSignallingMinDuration = VETO_SIGNALLING_MIN_DURATION;
config.vetoSignallingMaxDuration = VETO_SIGNALLING_MAX_DURATION;
config.vetoSignallingMinActiveDuration = VETO_SIGNALLING_MIN_ACTIVE_DURATION;
config.vetoSignallingDeactivationMaxDuration = VETO_SIGNALLING_DEACTIVATION_MAX_DURATION;

config.vetoCooldownDuration = VETO_COOLDOWN_DURATION;

config.rageQuitExtensionPeriodDuration = RAGE_QUIT_EXTENSION_PERIOD_DURATION;
config.rageQuitEthWithdrawalsMinDelay = RAGE_QUIT_ETH_WITHDRAWALS_MIN_DELAY;
config.rageQuitEthWithdrawalsMaxDelay = RAGE_QUIT_ETH_WITHDRAWALS_MAX_DELAY;
config.rageQuitEthWithdrawalsDelayGrowth = RAGE_QUIT_ETH_WITHDRAWALS_DELAY_GROWTH;
}
}
37 changes: 28 additions & 9 deletions contracts/ResealManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,76 @@ import {ISealable} from "./interfaces/ISealable.sol";
import {ITimelock} from "./interfaces/ITimelock.sol";
import {IResealManager} from "./interfaces/IResealManager.sol";

/// @title ResealManager
/// @dev Allows to extend pause of temporarily paused contracts to permanent pause or resume it.
/// @title Reseal Manager
/// @notice Allows to extend pause of temporarily paused contracts to permanent pause or resume it.
contract ResealManager is IResealManager {
// ---
// Errors
// ---

error SealableWrongPauseState();
error CallerIsNotGovernance(address caller);

// ---
// Immutables & Constants
// ---

uint256 public constant PAUSE_INFINITELY = type(uint256).max;
ITimelock public immutable EMERGENCY_PROTECTED_TIMELOCK;

// ---
// Constructor
// ---

/// @notice Initializes the ResealManager contract.
/// @param emergencyProtectedTimelock The address of the EmergencyProtectedTimelock contract.
constructor(ITimelock emergencyProtectedTimelock) {
EMERGENCY_PROTECTED_TIMELOCK = ITimelock(emergencyProtectedTimelock);
EMERGENCY_PROTECTED_TIMELOCK = emergencyProtectedTimelock;
}

// ---
// Main Functionality
// ---

/// @notice Extends the pause of the specified sealable contract.
/// @dev Works only if conditions are met:
/// - ResealManager has PAUSE_ROLE for target contract;
/// - Contract are paused until timestamp after current timestamp and not for infinite time;
/// - The DAO governance is blocked by DualGovernance;
/// - Function is called by the governance contract.
/// @param sealable The address of the sealable contract.
function reseal(address sealable) public {
function reseal(address sealable) external {
_checkCallerIsGovernance();

uint256 sealableResumeSinceTimestamp = ISealable(sealable).getResumeSinceTimestamp();
if (sealableResumeSinceTimestamp < block.timestamp || sealableResumeSinceTimestamp == PAUSE_INFINITELY) {
if (block.timestamp >= sealableResumeSinceTimestamp || sealableResumeSinceTimestamp == PAUSE_INFINITELY) {
revert SealableWrongPauseState();
}
Address.functionCall(sealable, abi.encodeWithSelector(ISealable.resume.selector));
Address.functionCall(sealable, abi.encodeWithSelector(ISealable.pauseFor.selector, PAUSE_INFINITELY));
}

/// @notice Resumes the specified sealable contract if it is scheduled to resume in the future.
/// @notice Resumes the specified sealable contract if it is paused.
/// @dev Works only if conditions are met:
/// - ResealManager has RESUME_ROLE for target contract;
/// - Contract are paused until timestamp after current timestamp;
/// - Function is called by the governance contract.
/// @param sealable The address of the sealable contract.
function resume(address sealable) public {
function resume(address sealable) external {
_checkCallerIsGovernance();

uint256 sealableResumeSinceTimestamp = ISealable(sealable).getResumeSinceTimestamp();
if (sealableResumeSinceTimestamp < block.timestamp) {
if (block.timestamp >= sealableResumeSinceTimestamp) {
revert SealableWrongPauseState();
}
Address.functionCall(sealable, abi.encodeWithSelector(ISealable.resume.selector));
}

// ---
// Internal methods
// ---

/// @notice Ensures that the function can only be called by the governance address.
/// @dev Reverts if the sender is not the governance address.
function _checkCallerIsGovernance() internal view {
address governance = EMERGENCY_PROTECTED_TIMELOCK.getGovernance();
if (msg.sender != governance) {
Expand Down
Loading

0 comments on commit e99d4fc

Please sign in to comment.