github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/universal/ProxyAdmin.t.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 import { Test } from "forge-std/Test.sol"; 5 import { Proxy } from "src/universal/Proxy.sol"; 6 import { ProxyAdmin } from "src/universal/ProxyAdmin.sol"; 7 import { SimpleStorage } from "test/universal/Proxy.t.sol"; 8 import { L1ChugSplashProxy } from "src/legacy/L1ChugSplashProxy.sol"; 9 import { ResolvedDelegateProxy } from "src/legacy/ResolvedDelegateProxy.sol"; 10 import { AddressManager } from "src/legacy/AddressManager.sol"; 11 12 contract ProxyAdmin_Test is Test { 13 address alice = address(64); 14 15 Proxy proxy; 16 L1ChugSplashProxy chugsplash; 17 ResolvedDelegateProxy resolved; 18 19 AddressManager addressManager; 20 21 ProxyAdmin admin; 22 23 SimpleStorage implementation; 24 25 function setUp() external { 26 // Deploy the proxy admin 27 admin = new ProxyAdmin(alice); 28 // Deploy the standard proxy 29 proxy = new Proxy(address(admin)); 30 31 // Deploy the legacy L1ChugSplashProxy with the admin as the owner 32 chugsplash = new L1ChugSplashProxy(address(admin)); 33 34 // Deploy the legacy AddressManager 35 addressManager = new AddressManager(); 36 // The proxy admin must be the new owner of the address manager 37 addressManager.transferOwnership(address(admin)); 38 // Deploy a legacy ResolvedDelegateProxy with the name `a`. 39 // Whatever `a` is set to in AddressManager will be the address 40 // that is used for the implementation. 41 resolved = new ResolvedDelegateProxy(addressManager, "a"); 42 43 // Impersonate alice for setting up the admin. 44 vm.startPrank(alice); 45 // Set the address of the address manager in the admin so that it 46 // can resolve the implementation address of legacy 47 // ResolvedDelegateProxy based proxies. 48 admin.setAddressManager(addressManager); 49 // Set the reverse lookup of the ResolvedDelegateProxy 50 // proxy 51 admin.setImplementationName(address(resolved), "a"); 52 53 // Set the proxy types 54 admin.setProxyType(address(proxy), ProxyAdmin.ProxyType.ERC1967); 55 admin.setProxyType(address(chugsplash), ProxyAdmin.ProxyType.CHUGSPLASH); 56 admin.setProxyType(address(resolved), ProxyAdmin.ProxyType.RESOLVED); 57 vm.stopPrank(); 58 59 implementation = new SimpleStorage(); 60 } 61 62 function test_setImplementationName_succeeds() external { 63 vm.prank(alice); 64 admin.setImplementationName(address(1), "foo"); 65 assertEq(admin.implementationName(address(1)), "foo"); 66 } 67 68 function test_setAddressManager_notOwner_reverts() external { 69 vm.expectRevert("Ownable: caller is not the owner"); 70 admin.setAddressManager(AddressManager((address(0)))); 71 } 72 73 function test_setImplementationName_notOwner_reverts() external { 74 vm.expectRevert("Ownable: caller is not the owner"); 75 admin.setImplementationName(address(0), "foo"); 76 } 77 78 function test_setProxyType_notOwner_reverts() external { 79 vm.expectRevert("Ownable: caller is not the owner"); 80 admin.setProxyType(address(0), ProxyAdmin.ProxyType.CHUGSPLASH); 81 } 82 83 function test_owner_succeeds() external { 84 assertEq(admin.owner(), alice); 85 } 86 87 function test_proxyType_succeeds() external { 88 assertEq(uint256(admin.proxyType(address(proxy))), uint256(ProxyAdmin.ProxyType.ERC1967)); 89 assertEq(uint256(admin.proxyType(address(chugsplash))), uint256(ProxyAdmin.ProxyType.CHUGSPLASH)); 90 assertEq(uint256(admin.proxyType(address(resolved))), uint256(ProxyAdmin.ProxyType.RESOLVED)); 91 } 92 93 function test_erc1967GetProxyImplementation_succeeds() external { 94 getProxyImplementation(payable(proxy)); 95 } 96 97 function test_chugsplashGetProxyImplementation_succeeds() external { 98 getProxyImplementation(payable(chugsplash)); 99 } 100 101 function test_delegateResolvedGetProxyImplementation_succeeds() external { 102 getProxyImplementation(payable(resolved)); 103 } 104 105 function getProxyImplementation(address payable _proxy) internal { 106 { 107 address impl = admin.getProxyImplementation(_proxy); 108 assertEq(impl, address(0)); 109 } 110 111 vm.prank(alice); 112 admin.upgrade(_proxy, address(implementation)); 113 114 { 115 address impl = admin.getProxyImplementation(_proxy); 116 assertEq(impl, address(implementation)); 117 } 118 } 119 120 function test_erc1967GetProxyAdmin_succeeds() external { 121 getProxyAdmin(payable(proxy)); 122 } 123 124 function test_chugsplashGetProxyAdmin_succeeds() external { 125 getProxyAdmin(payable(chugsplash)); 126 } 127 128 function test_delegateResolvedGetProxyAdmin_succeeds() external { 129 getProxyAdmin(payable(resolved)); 130 } 131 132 function getProxyAdmin(address payable _proxy) internal { 133 address owner = admin.getProxyAdmin(_proxy); 134 assertEq(owner, address(admin)); 135 } 136 137 function test_erc1967ChangeProxyAdmin_succeeds() external { 138 changeProxyAdmin(payable(proxy)); 139 } 140 141 function test_chugsplashChangeProxyAdmin_succeeds() external { 142 changeProxyAdmin(payable(chugsplash)); 143 } 144 145 function test_delegateResolvedChangeProxyAdmin_succeeds() external { 146 changeProxyAdmin(payable(resolved)); 147 } 148 149 function changeProxyAdmin(address payable _proxy) internal { 150 ProxyAdmin.ProxyType proxyType = admin.proxyType(address(_proxy)); 151 152 vm.prank(alice); 153 admin.changeProxyAdmin(_proxy, address(128)); 154 155 // The proxy is no longer the admin and can 156 // no longer call the proxy interface except for 157 // the ResolvedDelegate type on which anybody can 158 // call the admin interface. 159 if (proxyType == ProxyAdmin.ProxyType.ERC1967) { 160 vm.expectRevert("Proxy: implementation not initialized"); 161 admin.getProxyAdmin(_proxy); 162 } else if (proxyType == ProxyAdmin.ProxyType.CHUGSPLASH) { 163 vm.expectRevert("L1ChugSplashProxy: implementation is not set yet"); 164 admin.getProxyAdmin(_proxy); 165 } else if (proxyType == ProxyAdmin.ProxyType.RESOLVED) { 166 // Just an empty block to show that all cases are covered 167 } else { 168 vm.expectRevert("ProxyAdmin: unknown proxy type"); 169 } 170 171 // Call the proxy contract directly to get the admin. 172 // Different proxy types have different interfaces. 173 vm.prank(address(128)); 174 if (proxyType == ProxyAdmin.ProxyType.ERC1967) { 175 assertEq(Proxy(payable(_proxy)).admin(), address(128)); 176 } else if (proxyType == ProxyAdmin.ProxyType.CHUGSPLASH) { 177 assertEq(L1ChugSplashProxy(payable(_proxy)).getOwner(), address(128)); 178 } else if (proxyType == ProxyAdmin.ProxyType.RESOLVED) { 179 assertEq(addressManager.owner(), address(128)); 180 } else { 181 assert(false); 182 } 183 } 184 185 function test_erc1967Upgrade_succeeds() external { 186 upgrade(payable(proxy)); 187 } 188 189 function test_chugsplashUpgrade_succeeds() external { 190 upgrade(payable(chugsplash)); 191 } 192 193 function test_delegateResolvedUpgrade_succeeds() external { 194 upgrade(payable(resolved)); 195 } 196 197 function upgrade(address payable _proxy) internal { 198 vm.prank(alice); 199 admin.upgrade(_proxy, address(implementation)); 200 201 address impl = admin.getProxyImplementation(_proxy); 202 assertEq(impl, address(implementation)); 203 } 204 205 function test_erc1967UpgradeAndCall_succeeds() external { 206 upgradeAndCall(payable(proxy)); 207 } 208 209 function test_chugsplashUpgradeAndCall_succeeds() external { 210 upgradeAndCall(payable(chugsplash)); 211 } 212 213 function test_delegateResolvedUpgradeAndCall_succeeds() external { 214 upgradeAndCall(payable(resolved)); 215 } 216 217 function upgradeAndCall(address payable _proxy) internal { 218 vm.prank(alice); 219 admin.upgradeAndCall(_proxy, address(implementation), abi.encodeWithSelector(SimpleStorage.set.selector, 1, 1)); 220 221 address impl = admin.getProxyImplementation(_proxy); 222 assertEq(impl, address(implementation)); 223 224 uint256 got = SimpleStorage(address(_proxy)).get(1); 225 assertEq(got, 1); 226 } 227 228 function test_onlyOwner_notOwner_reverts() external { 229 vm.expectRevert("Ownable: caller is not the owner"); 230 admin.changeProxyAdmin(payable(proxy), address(0)); 231 232 vm.expectRevert("Ownable: caller is not the owner"); 233 admin.upgrade(payable(proxy), address(implementation)); 234 235 vm.expectRevert("Ownable: caller is not the owner"); 236 admin.upgradeAndCall(payable(proxy), address(implementation), hex""); 237 } 238 239 function test_isUpgrading_succeeds() external { 240 assertEq(false, admin.isUpgrading()); 241 242 vm.prank(alice); 243 admin.setUpgrading(true); 244 assertEq(true, admin.isUpgrading()); 245 } 246 }