Commit 7986507d authored by Maurelian's avatar Maurelian

feat(ctb): Add minimal SuperchainConfig with pause

The rest of the system does not yet read from the SuperchainConfig.

fix scc tests
parent d8bdedb3
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import { ISemver } from "src/universal/ISemver.sol";
import { Storage } from "src/libraries/Storage.sol";
import { Constants } from "src/libraries/Constants.sol";
/// @custom:audit none This contracts is not yet audited.
/// @title SuperchainConfig
/// @notice The SuperchainConfig contract is used to manage configuration of global superchain values.
contract SuperchainConfig is Initializable, ISemver {
/// @notice Enum representing different types of updates.
/// @custom:value GUARDIAN Represents an update to the guardian.
enum UpdateType { GUARDIAN }
/// @notice Whether or not the Superchain is paused.
bytes32 public constant PAUSED_SLOT = bytes32(uint256(keccak256("superchainConfig.paused")) - 1);
/// @notice The address of the guardian, which can pause withdrawals from the System.
/// It can only be modified by an upgrade.
bytes32 public constant GUARDIAN_SLOT = bytes32(uint256(keccak256("superchainConfig.guardian")) - 1);
/// @notice Emitted when the pause is triggered.
/// @param identifier A string helping to identify provenance of the pause transaction.
event Paused(string identifier);
/// @notice Emitted when the pause is lifted.
event Unpaused();
/// @notice Emitted when configuration is updated.
/// @param updateType Type of update.
/// @param data Encoded update data.
event ConfigUpdate(UpdateType indexed updateType, bytes data);
/// @notice Semantic version.
/// @custom:semver 1.0.0
string public constant version = "1.0.0";
/// @notice Constructs the SuperchainConfig contract.
constructor() {
initialize({ _guardian: address(0) });
}
/// @notice Initializer.
/// @param _guardian Address of the guardian, can pause the OptimismPortal.
function initialize(address _guardian) public initializer {
_setGuardian(_guardian);
}
/// @notice Getter for the guardian address.
function guardian() public view returns (address guardian_) {
guardian_ = Storage.getAddress(GUARDIAN_SLOT);
}
/// @notice Getter for the current paused status.
function paused() public view returns (bool paused_) {
paused_ = (Storage.getUint(PAUSED_SLOT) == 1);
}
/// @notice Pauses withdrawals.
/// @param _identifier (Optional) A string to identify provenance of the pause transaction.
function pause(string memory _identifier) external {
require(msg.sender == guardian(), "SuperchainConfig: only guardian can pause");
Storage.setUint(PAUSED_SLOT, 1);
emit Paused(_identifier);
}
/// @notice Unpauses withdrawals.
function unpause() external {
require(msg.sender == guardian(), "SuperchainConfig: only guardian can unpause");
Storage.setUint(PAUSED_SLOT, 0);
emit Unpaused();
}
/// @notice Sets the guardian address.
/// @param _guardian The new guardian address.
function _setGuardian(address _guardian) internal {
Storage.setAddress(GUARDIAN_SLOT, _guardian);
emit ConfigUpdate(UpdateType.GUARDIAN, abi.encode(_guardian));
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { CommonTest } from "test/setup/CommonTest.sol";
// Libraries
import { Types } from "src/libraries/Types.sol";
import { Hashing } from "src/libraries/Hashing.sol";
// Target contract dependencies
import { Proxy } from "src/universal/Proxy.sol";
// Target contract
import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
contract SuperchainConfig_Init_Test is CommonTest {
/// @dev Tests that initialization sets the correct values. These are defined in CommonTest.sol.
function test_initialize_values_succeeds() external {
assertFalse(superchainConfig.paused());
assertEq(superchainConfig.guardian(), guardian);
}
}
contract SuperchainConfig_Pause_TestFail is CommonTest {
/// @dev Tests that `pause` reverts when called by a non-guardian.
function test_pause_notGuardian_reverts() external {
assertFalse(superchainConfig.paused());
assertTrue(superchainConfig.guardian() != alice);
vm.expectRevert("SuperchainConfig: only guardian can pause");
vm.prank(alice);
superchainConfig.pause("identifier");
assertFalse(superchainConfig.paused());
}
}
contract SuperchainConfig_Pause_Test is CommonTest {
/// @dev Tests that `pause` successfully pauses
/// when called by the guardian.
function test_pause_succeeds() external {
assertFalse(superchainConfig.paused());
vm.expectEmit(address(superchainConfig));
emit Paused("identifier");
vm.prank(guardian);
superchainConfig.pause("identifier");
assertTrue(superchainConfig.paused());
}
}
contract SuperchainConfig_Unpause_TestFail is CommonTest {
/// @dev Tests that `unpause` reverts when called by a non-guardian.
function test_unpause_notGuardian_reverts() external {
_pause();
assertTrue(superchainConfig.guardian() != alice);
vm.expectRevert("SuperchainConfig: only guardian can unpause");
vm.prank(alice);
superchainConfig.unpause();
assertTrue(superchainConfig.paused());
}
}
contract SuperchainConfig_Unpause_Test is CommonTest {
/// @dev Tests that `unpause` successfully unpauses
/// when called by the guardian.
function test_unpause_succeeds() external {
_pause();
vm.expectEmit(address(superchainConfig));
emit Unpaused();
vm.prank(guardian);
superchainConfig.unpause();
assertFalse(superchainConfig.paused());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment