ProxyAdmin.t.sol 8.6 KB
Newer Older
1
// SPDX-License-Identifier: MIT
2
pragma solidity 0.8.15;
3 4 5 6 7 8

import { Test } from "forge-std/Test.sol";
import { Proxy } from "../universal/Proxy.sol";
import { ProxyAdmin } from "../universal/ProxyAdmin.sol";
import { SimpleStorage } from "./Proxy.t.sol";
import { L1ChugSplashProxy } from "../legacy/L1ChugSplashProxy.sol";
9 10
import { ResolvedDelegateProxy } from "../legacy/ResolvedDelegateProxy.sol";
import { AddressManager } from "../legacy/AddressManager.sol";
11 12 13 14 15 16

contract ProxyAdmin_Test is Test {
    address alice = address(64);

    Proxy proxy;
    L1ChugSplashProxy chugsplash;
17
    ResolvedDelegateProxy resolved;
18

19
    AddressManager addressManager;
20 21 22 23 24 25 26 27 28 29 30 31 32 33

    ProxyAdmin admin;

    SimpleStorage implementation;

    function setUp() external {
        // Deploy the proxy admin
        admin = new ProxyAdmin(alice);
        // Deploy the standard proxy
        proxy = new Proxy(address(admin));

        // Deploy the legacy L1ChugSplashProxy with the admin as the owner
        chugsplash = new L1ChugSplashProxy(address(admin));

34 35
        // Deploy the legacy AddressManager
        addressManager = new AddressManager();
36 37
        // The proxy admin must be the new owner of the address manager
        addressManager.transferOwnership(address(admin));
38 39
        // Deploy a legacy ResolvedDelegateProxy with the name `a`.
        // 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 44
        // Impersonate alice for setting up the admin.
        vm.startPrank(alice);
45 46
        // Set the address of the address manager in the admin so that it
        // can resolve the implementation address of legacy
47
        // ResolvedDelegateProxy based proxies.
48
        admin.setAddressManager(addressManager);
49
        // Set the reverse lookup of the ResolvedDelegateProxy
50 51 52 53
        // proxy
        admin.setImplementationName(address(resolved), "a");

        // Set the proxy types
54
        admin.setProxyType(address(proxy), ProxyAdmin.ProxyType.ERC1967);
55 56
        admin.setProxyType(address(chugsplash), ProxyAdmin.ProxyType.CHUGSPLASH);
        admin.setProxyType(address(resolved), ProxyAdmin.ProxyType.RESOLVED);
57
        vm.stopPrank();
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

        implementation = new SimpleStorage();
    }

    function test_setImplementationName() external {
        vm.prank(alice);
        admin.setImplementationName(address(1), "foo");
        assertEq(
            admin.implementationName(address(1)),
            "foo"
        );
    }

    function test_onlyOwnerSetAddressManager() external {
        vm.expectRevert("UNAUTHORIZED");
73
        admin.setAddressManager(AddressManager((address(0))));
74 75 76 77 78 79 80 81 82
    }

    function test_onlyOwnerSetImplementationName() external {
        vm.expectRevert("UNAUTHORIZED");
        admin.setImplementationName(address(0), "foo");
    }

    function test_onlyOwnerSetProxyType() external {
        vm.expectRevert("UNAUTHORIZED");
83
        admin.setProxyType(address(0), ProxyAdmin.ProxyType.CHUGSPLASH);
84 85 86 87 88 89 90 91 92
    }

    function test_owner() external {
        assertEq(admin.owner(), alice);
    }

    function test_proxyType() external {
        assertEq(
            uint256(admin.proxyType(address(proxy))),
93
            uint256(ProxyAdmin.ProxyType.ERC1967)
94 95 96
        );
        assertEq(
            uint256(admin.proxyType(address(chugsplash))),
97
            uint256(ProxyAdmin.ProxyType.CHUGSPLASH)
98 99 100
        );
        assertEq(
            uint256(admin.proxyType(address(resolved))),
101
            uint256(ProxyAdmin.ProxyType.RESOLVED)
102 103 104
        );
    }

105
    function test_erc1967GetProxyImplementation() external {
106
        getProxyImplementation(payable(proxy));
107 108 109
    }

    function test_chugsplashGetProxyImplementation() external {
110
        getProxyImplementation(payable(chugsplash));
111 112 113
    }

    function test_delegateResolvedGetProxyImplementation() external {
114
        getProxyImplementation(payable(resolved));
115 116
    }

117
    function getProxyImplementation(address payable _proxy) internal {
118 119 120 121 122 123 124 125 126 127 128 129 130 131
        {
            address impl = admin.getProxyImplementation(_proxy);
            assertEq(impl, address(0));
        }

        vm.prank(alice);
        admin.upgrade(_proxy, address(implementation));

        {
            address impl = admin.getProxyImplementation(_proxy);
            assertEq(impl, address(implementation));
        }
    }

132
    function test_erc1967GetProxyAdmin() external {
133
        getProxyAdmin(payable(proxy));
134 135 136
    }

    function test_chugsplashGetProxyAdmin() external {
137
        getProxyAdmin(payable(chugsplash));
138 139 140
    }

    function test_delegateResolvedGetProxyAdmin() external {
141
        getProxyAdmin(payable(resolved));
142 143
    }

144
    function getProxyAdmin(address payable _proxy) internal {
145 146 147 148
        address owner = admin.getProxyAdmin(_proxy);
        assertEq(owner, address(admin));
    }

149
    function test_erc1967ChangeProxyAdmin() external {
150
        changeProxyAdmin(payable(proxy));
151 152 153
    }

    function test_chugsplashChangeProxyAdmin() external {
154
        changeProxyAdmin(payable(chugsplash));
155 156 157
    }

    function test_delegateResolvedChangeProxyAdmin() external {
158
        changeProxyAdmin(payable(resolved));
159 160
    }

161
    function changeProxyAdmin(address payable _proxy) internal {
162 163 164 165 166
        ProxyAdmin.ProxyType proxyType = admin.proxyType(address(_proxy));

        vm.prank(alice);
        admin.changeProxyAdmin(_proxy, address(128));

167
        // The proxy is no longer the admin and can
168
        // no longer call the proxy interface except for
169 170 171 172
        // the ResolvedDelegate type on which anybody can
        // call the admin interface.
        if (proxyType == ProxyAdmin.ProxyType.ERC1967) {
            vm.expectRevert("Proxy: implementation not initialized");
173
            admin.getProxyAdmin(_proxy);
174
        } else if (proxyType == ProxyAdmin.ProxyType.CHUGSPLASH) {
175 176
            vm.expectRevert("L1ChugSplashProxy: implementation is not set yet");
            admin.getProxyAdmin(_proxy);
177
        } else if (proxyType == ProxyAdmin.ProxyType.RESOLVED) {
178 179 180
            // Just an empty block to show that all cases are covered
        } else {
            vm.expectRevert("ProxyAdmin: unknown proxy type");
181 182 183 184 185
        }

        // Call the proxy contract directly to get the admin.
        // Different proxy types have different interfaces.
        vm.prank(address(128));
186
        if (proxyType == ProxyAdmin.ProxyType.ERC1967) {
187
            assertEq(Proxy(payable(_proxy)).admin(), address(128));
188
        } else if (proxyType == ProxyAdmin.ProxyType.CHUGSPLASH) {
189 190 191 192
            assertEq(
                L1ChugSplashProxy(payable(_proxy)).getOwner(),
                address(128)
            );
193
        } else if (proxyType == ProxyAdmin.ProxyType.RESOLVED) {
194 195 196 197 198 199 200 201 202
            assertEq(
                addressManager.owner(),
                address(128)
            );
        } else {
            assert(false);
        }
    }

203
    function test_erc1967Upgrade() external {
204
        upgrade(payable(proxy));
205 206 207
    }

    function test_chugsplashUpgrade() external {
208
        upgrade(payable(chugsplash));
209 210 211
    }

    function test_delegateResolvedUpgrade() external {
212
        upgrade(payable(resolved));
213 214
    }

215
    function upgrade(address payable _proxy) internal {
216 217 218 219 220 221 222
        vm.prank(alice);
        admin.upgrade(_proxy, address(implementation));

        address impl = admin.getProxyImplementation(_proxy);
        assertEq(impl, address(implementation));
    }

223
    function test_erc1967UpgradeAndCall() external {
224
        upgradeAndCall(payable(proxy));
225 226 227
    }

    function test_chugsplashUpgradeAndCall() external {
228
        upgradeAndCall(payable(chugsplash));
229 230 231
    }

    function test_delegateResolvedUpgradeAndCall() external {
232
        upgradeAndCall(payable(resolved));
233 234
    }

235
    function upgradeAndCall(address payable _proxy) internal {
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
        vm.prank(alice);
        admin.upgradeAndCall(
            _proxy,
            address(implementation),
            abi.encodeWithSelector(SimpleStorage.set.selector, 1, 1)
        );

        address impl = admin.getProxyImplementation(_proxy);
        assertEq(impl, address(implementation));

        uint256 got = SimpleStorage(address(_proxy)).get(1);
        assertEq(got, 1);
    }

    function test_onlyOwner() external {
        vm.expectRevert("UNAUTHORIZED");
252
        admin.changeProxyAdmin(payable(proxy), address(0));
253 254

        vm.expectRevert("UNAUTHORIZED");
255
        admin.upgrade(payable(proxy), address(implementation));
256 257

        vm.expectRevert("UNAUTHORIZED");
258
        admin.upgradeAndCall(payable(proxy), address(implementation), hex"");
259 260 261 262 263 264 265 266 267 268
    }

    function test_isUpgrading() external {
        assertEq(false, admin.isUpgrading());

        vm.prank(alice);
        admin.setUpgrading(true);
        assertEq(true, admin.isUpgrading());
    }
}