From 88b672938b6ff58548e5695518218ce408946ec6 Mon Sep 17 00:00:00 2001 From: Cory Dickson Date: Mon, 5 Aug 2024 14:55:53 -0400 Subject: [PATCH] Add files --- src/ProxyAdmin.sol | 103 +++++++++++++++++++++++++++++++++++++++++++++ src/Timelock.sol | 16 +++++++ 2 files changed, 119 insertions(+) create mode 100644 src/ProxyAdmin.sol create mode 100644 src/Timelock.sol diff --git a/src/ProxyAdmin.sol b/src/ProxyAdmin.sol new file mode 100644 index 0000000..6c8cac3 --- /dev/null +++ b/src/ProxyAdmin.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; + +contract ProxyAdmin { + event OwnerUpdated(address indexed owner, bool isOwner); + + mapping(address => bool) public owners; + + modifier onlyOwners() { + require(owners[msg.sender], "ProxyAdmin: caller is not one of the owners"); + _; + } + + /** + * @param _owners Array of addresses to set as owners. + */ + constructor(address[] memory _owners) { + for (uint256 i = 0; i < _owners.length; i++) { + owners[_owners[i]] = true; + emit OwnerUpdated(_owners[i], true); + } + } + + /** + * @notice Toggle an owner on or off. + * @param owner Address of the owner to update. + * @param isOwner Boolean indicating if the address should be an owner. + */ + function updateOwner(address owner, bool isOwner) public onlyOwners { + owners[owner] = isOwner; + emit OwnerUpdated(owner, isOwner); + } + + /** + * @dev Returns the current implementation of `proxy`. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + function getProxyImplementation(TransparentUpgradeableProxy proxy) public view returns (address) { + // We need to manually run the static call since the getter cannot be flagged as view + // bytes4(keccak256("implementation()")) == 0x5c60da1b + (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); + require(success); + return abi.decode(returndata, (address)); + } + + /** + * @dev Returns the current admin of `proxy`. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + function getProxyAdmin(TransparentUpgradeableProxy proxy) public view returns (address) { + // We need to manually run the static call since the getter cannot be flagged as view + // bytes4(keccak256("admin()")) == 0xf851a440 + (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); + require(success); + return abi.decode(returndata, (address)); + } + + /** + * @dev Changes the admin of `proxy` to `newAdmin`. + * + * Requirements: + * + * - This contract must be the current admin of `proxy`. + */ + function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public onlyOwners { + proxy.changeAdmin(newAdmin); + } + + /** + * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + function upgrade(TransparentUpgradeableProxy proxy, address implementation) public onlyOwners { + proxy.upgradeTo(implementation); + } + + /** + * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See + * {TransparentUpgradeableProxy-upgradeToAndCall}. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) + public + payable + onlyOwners + { + proxy.upgradeToAndCall{value: msg.value}(implementation, data); + } +} diff --git a/src/Timelock.sol b/src/Timelock.sol new file mode 100644 index 0000000..4573a0c --- /dev/null +++ b/src/Timelock.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {TimelockControllerUpgradeable} from + "@openzeppelin/contracts-upgradeable-v4/governance/TimelockControllerUpgradeable.sol"; + +contract Timelock is TimelockControllerUpgradeable { + function initialize(uint256 minDelay, address governor, address admin) public initializer { + address[] memory proposers = new address[](1); + proposers[0] = governor; + address[] memory executors = new address[](1); + executors[0] = governor; + + __TimelockController_init(minDelay, proposers, executors, admin); + } +}