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 }