github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/universal/ProxyAdmin.sol (about)

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity 0.8.15;
     3  
     4  import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
     5  import { Proxy } from "src/universal/Proxy.sol";
     6  import { AddressManager } from "src/legacy/AddressManager.sol";
     7  import { L1ChugSplashProxy } from "src/legacy/L1ChugSplashProxy.sol";
     8  import { Constants } from "src/libraries/Constants.sol";
     9  
    10  /// @title IStaticERC1967Proxy
    11  /// @notice IStaticERC1967Proxy is a static version of the ERC1967 proxy interface.
    12  interface IStaticERC1967Proxy {
    13      function implementation() external view returns (address);
    14  
    15      function admin() external view returns (address);
    16  }
    17  
    18  /// @title IStaticL1ChugSplashProxy
    19  /// @notice IStaticL1ChugSplashProxy is a static version of the ChugSplash proxy interface.
    20  interface IStaticL1ChugSplashProxy {
    21      function getImplementation() external view returns (address);
    22  
    23      function getOwner() external view returns (address);
    24  }
    25  
    26  /// @title ProxyAdmin
    27  /// @notice This is an auxiliary contract meant to be assigned as the admin of an ERC1967 Proxy,
    28  ///         based on the OpenZeppelin implementation. It has backwards compatibility logic to work
    29  ///         with the various types of proxies that have been deployed by Optimism in the past.
    30  contract ProxyAdmin is Ownable {
    31      /// @notice The proxy types that the ProxyAdmin can manage.
    32      /// @custom:value ERC1967    Represents an ERC1967 compliant transparent proxy interface.
    33      /// @custom:value CHUGSPLASH Represents the Chugsplash proxy interface (legacy).
    34      /// @custom:value RESOLVED   Represents the ResolvedDelegate proxy (legacy).
    35      enum ProxyType {
    36          ERC1967,
    37          CHUGSPLASH,
    38          RESOLVED
    39      }
    40  
    41      /// @notice A mapping of proxy types, used for backwards compatibility.
    42      mapping(address => ProxyType) public proxyType;
    43  
    44      /// @notice A reverse mapping of addresses to names held in the AddressManager. This must be
    45      ///         manually kept up to date with changes in the AddressManager for this contract
    46      ///         to be able to work as an admin for the ResolvedDelegateProxy type.
    47      mapping(address => string) public implementationName;
    48  
    49      /// @notice The address of the address manager, this is required to manage the
    50      ///         ResolvedDelegateProxy type.
    51      AddressManager public addressManager;
    52  
    53      /// @notice A legacy upgrading indicator used by the old Chugsplash Proxy.
    54      bool internal upgrading;
    55  
    56      /// @param _owner Address of the initial owner of this contract.
    57      constructor(address _owner) Ownable() {
    58          _transferOwnership(_owner);
    59      }
    60  
    61      /// @notice Sets the proxy type for a given address. Only required for non-standard (legacy)
    62      ///         proxy types.
    63      /// @param _address Address of the proxy.
    64      /// @param _type    Type of the proxy.
    65      function setProxyType(address _address, ProxyType _type) external onlyOwner {
    66          proxyType[_address] = _type;
    67      }
    68  
    69      /// @notice Sets the implementation name for a given address. Only required for
    70      ///         ResolvedDelegateProxy type proxies that have an implementation name.
    71      /// @param _address Address of the ResolvedDelegateProxy.
    72      /// @param _name    Name of the implementation for the proxy.
    73      function setImplementationName(address _address, string memory _name) external onlyOwner {
    74          implementationName[_address] = _name;
    75      }
    76  
    77      /// @notice Set the address of the AddressManager. This is required to manage legacy
    78      ///         ResolvedDelegateProxy type proxy contracts.
    79      /// @param _address Address of the AddressManager.
    80      function setAddressManager(AddressManager _address) external onlyOwner {
    81          addressManager = _address;
    82      }
    83  
    84      /// @custom:legacy
    85      /// @notice Set an address in the address manager. Since only the owner of the AddressManager
    86      ///         can directly modify addresses and the ProxyAdmin will own the AddressManager, this
    87      ///         gives the owner of the ProxyAdmin the ability to modify addresses directly.
    88      /// @param _name    Name to set within the AddressManager.
    89      /// @param _address Address to attach to the given name.
    90      function setAddress(string memory _name, address _address) external onlyOwner {
    91          addressManager.setAddress(_name, _address);
    92      }
    93  
    94      /// @custom:legacy
    95      /// @notice Set the upgrading status for the Chugsplash proxy type.
    96      /// @param _upgrading Whether or not the system is upgrading.
    97      function setUpgrading(bool _upgrading) external onlyOwner {
    98          upgrading = _upgrading;
    99      }
   100  
   101      /// @custom:legacy
   102      /// @notice Legacy function used to tell ChugSplashProxy contracts if an upgrade is happening.
   103      /// @return Whether or not there is an upgrade going on. May not actually tell you whether an
   104      ///         upgrade is going on, since we don't currently plan to use this variable for anything
   105      ///         other than a legacy indicator to fix a UX bug in the ChugSplash proxy.
   106      function isUpgrading() external view returns (bool) {
   107          return upgrading;
   108      }
   109  
   110      /// @notice Returns the implementation of the given proxy address.
   111      /// @param _proxy Address of the proxy to get the implementation of.
   112      /// @return Address of the implementation of the proxy.
   113      function getProxyImplementation(address _proxy) external view returns (address) {
   114          ProxyType ptype = proxyType[_proxy];
   115          if (ptype == ProxyType.ERC1967) {
   116              return IStaticERC1967Proxy(_proxy).implementation();
   117          } else if (ptype == ProxyType.CHUGSPLASH) {
   118              return IStaticL1ChugSplashProxy(_proxy).getImplementation();
   119          } else if (ptype == ProxyType.RESOLVED) {
   120              return addressManager.getAddress(implementationName[_proxy]);
   121          } else {
   122              revert("ProxyAdmin: unknown proxy type");
   123          }
   124      }
   125  
   126      /// @notice Returns the admin of the given proxy address.
   127      /// @param _proxy Address of the proxy to get the admin of.
   128      /// @return Address of the admin of the proxy.
   129      function getProxyAdmin(address payable _proxy) external view returns (address) {
   130          ProxyType ptype = proxyType[_proxy];
   131          if (ptype == ProxyType.ERC1967) {
   132              return IStaticERC1967Proxy(_proxy).admin();
   133          } else if (ptype == ProxyType.CHUGSPLASH) {
   134              return IStaticL1ChugSplashProxy(_proxy).getOwner();
   135          } else if (ptype == ProxyType.RESOLVED) {
   136              return addressManager.owner();
   137          } else {
   138              revert("ProxyAdmin: unknown proxy type");
   139          }
   140      }
   141  
   142      /// @notice Updates the admin of the given proxy address.
   143      /// @param _proxy    Address of the proxy to update.
   144      /// @param _newAdmin Address of the new proxy admin.
   145      function changeProxyAdmin(address payable _proxy, address _newAdmin) external onlyOwner {
   146          ProxyType ptype = proxyType[_proxy];
   147          if (ptype == ProxyType.ERC1967) {
   148              Proxy(_proxy).changeAdmin(_newAdmin);
   149          } else if (ptype == ProxyType.CHUGSPLASH) {
   150              L1ChugSplashProxy(_proxy).setOwner(_newAdmin);
   151          } else if (ptype == ProxyType.RESOLVED) {
   152              addressManager.transferOwnership(_newAdmin);
   153          } else {
   154              revert("ProxyAdmin: unknown proxy type");
   155          }
   156      }
   157  
   158      /// @notice Changes a proxy's implementation contract.
   159      /// @param _proxy          Address of the proxy to upgrade.
   160      /// @param _implementation Address of the new implementation address.
   161      function upgrade(address payable _proxy, address _implementation) public onlyOwner {
   162          ProxyType ptype = proxyType[_proxy];
   163          if (ptype == ProxyType.ERC1967) {
   164              Proxy(_proxy).upgradeTo(_implementation);
   165          } else if (ptype == ProxyType.CHUGSPLASH) {
   166              L1ChugSplashProxy(_proxy).setStorage(
   167                  Constants.PROXY_IMPLEMENTATION_ADDRESS, bytes32(uint256(uint160(_implementation)))
   168              );
   169          } else if (ptype == ProxyType.RESOLVED) {
   170              string memory name = implementationName[_proxy];
   171              addressManager.setAddress(name, _implementation);
   172          } else {
   173              // It should not be possible to retrieve a ProxyType value which is not matched by
   174              // one of the previous conditions.
   175              assert(false);
   176          }
   177      }
   178  
   179      /// @notice Changes a proxy's implementation contract and delegatecalls the new implementation
   180      ///         with some given data. Useful for atomic upgrade-and-initialize calls.
   181      /// @param _proxy          Address of the proxy to upgrade.
   182      /// @param _implementation Address of the new implementation address.
   183      /// @param _data           Data to trigger the new implementation with.
   184      function upgradeAndCall(
   185          address payable _proxy,
   186          address _implementation,
   187          bytes memory _data
   188      )
   189          external
   190          payable
   191          onlyOwner
   192      {
   193          ProxyType ptype = proxyType[_proxy];
   194          if (ptype == ProxyType.ERC1967) {
   195              Proxy(_proxy).upgradeToAndCall{ value: msg.value }(_implementation, _data);
   196          } else {
   197              // reverts if proxy type is unknown
   198              upgrade(_proxy, _implementation);
   199              (bool success,) = _proxy.call{ value: msg.value }(_data);
   200              require(success, "ProxyAdmin: call to proxy after upgrade failed");
   201          }
   202      }
   203  }