ETH Price: $2,422.37 (+0.09%)

Transaction Decoder

Block:
21235536 at Nov-21-2024 10:33:47 AM +UTC
Transaction Fee:
0.000322759964153568 ETH $0.78
Gas Used:
27,894 Gas / 11.570945872 Gwei

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
13.518730541745209966 Eth13.518731170857336734 Eth0.000000629112126768
0x9a28888C...5b569d42F
0.000470254894588147 Eth
Nonce: 7
0.000147494930434579 Eth
Nonce: 8
0.000322759964153568

Execution Trace

ETH 0.0001 L1ChugSplashProxy.e11013dd( )
  • ProxyAdmin.STATICCALL( )
    File 1 of 2: L1ChugSplashProxy
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.15;
    /**
     * @title IL1ChugSplashDeployer
     */
    interface IL1ChugSplashDeployer {
        function isUpgrading() external view returns (bool);
    }
    /**
     * @custom:legacy
     * @title L1ChugSplashProxy
     * @notice Basic ChugSplash proxy contract for L1. Very close to being a normal proxy but has added
     *         functions `setCode` and `setStorage` for changing the code or storage of the contract.
     *
     *         Note for future developers: do NOT make anything in this contract 'public' unless you
     *         know what you're doing. Anything public can potentially have a function signature that
     *         conflicts with a signature attached to the implementation contract. Public functions
     *         SHOULD always have the `proxyCallIfNotOwner` modifier unless there's some *really* good
     *         reason not to have that modifier. And there almost certainly is not a good reason to not
     *         have that modifier. Beware!
     */
    contract L1ChugSplashProxy {
        /**
         * @notice "Magic" prefix. When prepended to some arbitrary bytecode and used to create a
         *         contract, the appended bytecode will be deployed as given.
         */
        bytes13 internal constant DEPLOY_CODE_PREFIX = 0x600D380380600D6000396000f3;
        /**
         * @notice bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
         */
        bytes32 internal constant IMPLEMENTATION_KEY =
            0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
        /**
         * @notice bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
         */
        bytes32 internal constant OWNER_KEY =
            0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
        /**
         * @notice Blocks a function from being called when the parent signals that the system should
         *         be paused via an isUpgrading function.
         */
        modifier onlyWhenNotPaused() {
            address owner = _getOwner();
            // We do a low-level call because there's no guarantee that the owner actually *is* an
            // L1ChugSplashDeployer contract and Solidity will throw errors if we do a normal call and
            // it turns out that it isn't the right type of contract.
            (bool success, bytes memory returndata) = owner.staticcall(
                abi.encodeWithSelector(IL1ChugSplashDeployer.isUpgrading.selector)
            );
            // If the call was unsuccessful then we assume that there's no "isUpgrading" method and we
            // can just continue as normal. We also expect that the return value is exactly 32 bytes
            // long. If this isn't the case then we can safely ignore the result.
            if (success && returndata.length == 32) {
                // Although the expected value is a *boolean*, it's safer to decode as a uint256 in the
                // case that the isUpgrading function returned something other than 0 or 1. But we only
                // really care about the case where this value is 0 (= false).
                uint256 ret = abi.decode(returndata, (uint256));
                require(ret == 0, "L1ChugSplashProxy: system is currently being upgraded");
            }
            _;
        }
        /**
         * @notice Makes a proxy call instead of triggering the given function when the caller is
         *         either the owner or the zero address. Caller can only ever be the zero address if
         *         this function is being called off-chain via eth_call, which is totally fine and can
         *         be convenient for client-side tooling. Avoids situations where the proxy and
         *         implementation share a sighash and the proxy function ends up being called instead
         *         of the implementation one.
         *
         *         Note: msg.sender == address(0) can ONLY be triggered off-chain via eth_call. If
         *         there's a way for someone to send a transaction with msg.sender == address(0) in any
         *         real context then we have much bigger problems. Primary reason to include this
         *         additional allowed sender is because the owner address can be changed dynamically
         *         and we do not want clients to have to keep track of the current owner in order to
         *         make an eth_call that doesn't trigger the proxied contract.
         */
        // slither-disable-next-line incorrect-modifier
        modifier proxyCallIfNotOwner() {
            if (msg.sender == _getOwner() || msg.sender == address(0)) {
                _;
            } else {
                // This WILL halt the call frame on completion.
                _doProxyCall();
            }
        }
        /**
         * @param _owner Address of the initial contract owner.
         */
        constructor(address _owner) {
            _setOwner(_owner);
        }
        // slither-disable-next-line locked-ether
        receive() external payable {
            // Proxy call by default.
            _doProxyCall();
        }
        // slither-disable-next-line locked-ether
        fallback() external payable {
            // Proxy call by default.
            _doProxyCall();
        }
        /**
         * @notice Sets the code that should be running behind this proxy.
         *
         *         Note: This scheme is a bit different from the standard proxy scheme where one would
         *         typically deploy the code separately and then set the implementation address. We're
         *         doing it this way because it gives us a lot more freedom on the client side. Can
         *         only be triggered by the contract owner.
         *
         * @param _code New contract code to run inside this contract.
         */
        function setCode(bytes memory _code) external proxyCallIfNotOwner {
            // Get the code hash of the current implementation.
            address implementation = _getImplementation();
            // If the code hash matches the new implementation then we return early.
            if (keccak256(_code) == _getAccountCodeHash(implementation)) {
                return;
            }
            // Create the deploycode by appending the magic prefix.
            bytes memory deploycode = abi.encodePacked(DEPLOY_CODE_PREFIX, _code);
            // Deploy the code and set the new implementation address.
            address newImplementation;
            assembly {
                newImplementation := create(0x0, add(deploycode, 0x20), mload(deploycode))
            }
            // Check that the code was actually deployed correctly. I'm not sure if you can ever
            // actually fail this check. Should only happen if the contract creation from above runs
            // out of gas but this parent execution thread does NOT run out of gas. Seems like we
            // should be doing this check anyway though.
            require(
                _getAccountCodeHash(newImplementation) == keccak256(_code),
                "L1ChugSplashProxy: code was not correctly deployed"
            );
            _setImplementation(newImplementation);
        }
        /**
         * @notice Modifies some storage slot within the proxy contract. Gives us a lot of power to
         *         perform upgrades in a more transparent way. Only callable by the owner.
         *
         * @param _key   Storage key to modify.
         * @param _value New value for the storage key.
         */
        function setStorage(bytes32 _key, bytes32 _value) external proxyCallIfNotOwner {
            assembly {
                sstore(_key, _value)
            }
        }
        /**
         * @notice Changes the owner of the proxy contract. Only callable by the owner.
         *
         * @param _owner New owner of the proxy contract.
         */
        function setOwner(address _owner) external proxyCallIfNotOwner {
            _setOwner(_owner);
        }
        /**
         * @notice Queries the owner of the proxy contract. Can only be called by the owner OR by
         *         making an eth_call and setting the "from" address to address(0).
         *
         * @return Owner address.
         */
        function getOwner() external proxyCallIfNotOwner returns (address) {
            return _getOwner();
        }
        /**
         * @notice Queries the implementation address. Can only be called by the owner OR by making an
         *         eth_call and setting the "from" address to address(0).
         *
         * @return Implementation address.
         */
        function getImplementation() external proxyCallIfNotOwner returns (address) {
            return _getImplementation();
        }
        /**
         * @notice Sets the implementation address.
         *
         * @param _implementation New implementation address.
         */
        function _setImplementation(address _implementation) internal {
            assembly {
                sstore(IMPLEMENTATION_KEY, _implementation)
            }
        }
        /**
         * @notice Changes the owner of the proxy contract.
         *
         * @param _owner New owner of the proxy contract.
         */
        function _setOwner(address _owner) internal {
            assembly {
                sstore(OWNER_KEY, _owner)
            }
        }
        /**
         * @notice Performs the proxy call via a delegatecall.
         */
        function _doProxyCall() internal onlyWhenNotPaused {
            address implementation = _getImplementation();
            require(implementation != address(0), "L1ChugSplashProxy: implementation is not set yet");
            assembly {
                // Copy calldata into memory at 0x0....calldatasize.
                calldatacopy(0x0, 0x0, calldatasize())
                // Perform the delegatecall, make sure to pass all available gas.
                let success := delegatecall(gas(), implementation, 0x0, calldatasize(), 0x0, 0x0)
                // Copy returndata into memory at 0x0....returndatasize. Note that this *will*
                // overwrite the calldata that we just copied into memory but that doesn't really
                // matter because we'll be returning in a second anyway.
                returndatacopy(0x0, 0x0, returndatasize())
                // Success == 0 means a revert. We'll revert too and pass the data up.
                if iszero(success) {
                    revert(0x0, returndatasize())
                }
                // Otherwise we'll just return and pass the data up.
                return(0x0, returndatasize())
            }
        }
        /**
         * @notice Queries the implementation address.
         *
         * @return Implementation address.
         */
        function _getImplementation() internal view returns (address) {
            address implementation;
            assembly {
                implementation := sload(IMPLEMENTATION_KEY)
            }
            return implementation;
        }
        /**
         * @notice Queries the owner of the proxy contract.
         *
         * @return Owner address.
         */
        function _getOwner() internal view returns (address) {
            address owner;
            assembly {
                owner := sload(OWNER_KEY)
            }
            return owner;
        }
        /**
         * @notice Gets the code hash for a given account.
         *
         * @param _account Address of the account to get a code hash for.
         *
         * @return Code hash for the account.
         */
        function _getAccountCodeHash(address _account) internal view returns (bytes32) {
            bytes32 codeHash;
            assembly {
                codeHash := extcodehash(_account)
            }
            return codeHash;
        }
    }
    

    File 2 of 2: ProxyAdmin
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.15;
    import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
    /**
     * @custom:legacy
     * @title AddressManager
     * @notice AddressManager is a legacy contract that was used in the old version of the Optimism
     *         system to manage a registry of string names to addresses. We now use a more standard
     *         proxy system instead, but this contract is still necessary for backwards compatibility
     *         with several older contracts.
     */
    contract AddressManager is Ownable {
        /**
         * @notice Mapping of the hashes of string names to addresses.
         */
        mapping(bytes32 => address) private addresses;
        /**
         * @notice Emitted when an address is modified in the registry.
         *
         * @param name       String name being set in the registry.
         * @param newAddress Address set for the given name.
         * @param oldAddress Address that was previously set for the given name.
         */
        event AddressSet(string indexed name, address newAddress, address oldAddress);
        /**
         * @notice Changes the address associated with a particular name.
         *
         * @param _name    String name to associate an address with.
         * @param _address Address to associate with the name.
         */
        function setAddress(string memory _name, address _address) external onlyOwner {
            bytes32 nameHash = _getNameHash(_name);
            address oldAddress = addresses[nameHash];
            addresses[nameHash] = _address;
            emit AddressSet(_name, _address, oldAddress);
        }
        /**
         * @notice Retrieves the address associated with a given name.
         *
         * @param _name Name to retrieve an address for.
         *
         * @return Address associated with the given name.
         */
        function getAddress(string memory _name) external view returns (address) {
            return addresses[_getNameHash(_name)];
        }
        /**
         * @notice Computes the hash of a name.
         *
         * @param _name Name to compute a hash for.
         *
         * @return Hash of the given name.
         */
        function _getNameHash(string memory _name) internal pure returns (bytes32) {
            return keccak256(abi.encodePacked(_name));
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.15;
    /**
     * @title IL1ChugSplashDeployer
     */
    interface IL1ChugSplashDeployer {
        function isUpgrading() external view returns (bool);
    }
    /**
     * @custom:legacy
     * @title L1ChugSplashProxy
     * @notice Basic ChugSplash proxy contract for L1. Very close to being a normal proxy but has added
     *         functions `setCode` and `setStorage` for changing the code or storage of the contract.
     *
     *         Note for future developers: do NOT make anything in this contract 'public' unless you
     *         know what you're doing. Anything public can potentially have a function signature that
     *         conflicts with a signature attached to the implementation contract. Public functions
     *         SHOULD always have the `proxyCallIfNotOwner` modifier unless there's some *really* good
     *         reason not to have that modifier. And there almost certainly is not a good reason to not
     *         have that modifier. Beware!
     */
    contract L1ChugSplashProxy {
        /**
         * @notice "Magic" prefix. When prepended to some arbitrary bytecode and used to create a
         *         contract, the appended bytecode will be deployed as given.
         */
        bytes13 internal constant DEPLOY_CODE_PREFIX = 0x600D380380600D6000396000f3;
        /**
         * @notice bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
         */
        bytes32 internal constant IMPLEMENTATION_KEY =
            0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
        /**
         * @notice bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
         */
        bytes32 internal constant OWNER_KEY =
            0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
        /**
         * @notice Blocks a function from being called when the parent signals that the system should
         *         be paused via an isUpgrading function.
         */
        modifier onlyWhenNotPaused() {
            address owner = _getOwner();
            // We do a low-level call because there's no guarantee that the owner actually *is* an
            // L1ChugSplashDeployer contract and Solidity will throw errors if we do a normal call and
            // it turns out that it isn't the right type of contract.
            (bool success, bytes memory returndata) = owner.staticcall(
                abi.encodeWithSelector(IL1ChugSplashDeployer.isUpgrading.selector)
            );
            // If the call was unsuccessful then we assume that there's no "isUpgrading" method and we
            // can just continue as normal. We also expect that the return value is exactly 32 bytes
            // long. If this isn't the case then we can safely ignore the result.
            if (success && returndata.length == 32) {
                // Although the expected value is a *boolean*, it's safer to decode as a uint256 in the
                // case that the isUpgrading function returned something other than 0 or 1. But we only
                // really care about the case where this value is 0 (= false).
                uint256 ret = abi.decode(returndata, (uint256));
                require(ret == 0, "L1ChugSplashProxy: system is currently being upgraded");
            }
            _;
        }
        /**
         * @notice Makes a proxy call instead of triggering the given function when the caller is
         *         either the owner or the zero address. Caller can only ever be the zero address if
         *         this function is being called off-chain via eth_call, which is totally fine and can
         *         be convenient for client-side tooling. Avoids situations where the proxy and
         *         implementation share a sighash and the proxy function ends up being called instead
         *         of the implementation one.
         *
         *         Note: msg.sender == address(0) can ONLY be triggered off-chain via eth_call. If
         *         there's a way for someone to send a transaction with msg.sender == address(0) in any
         *         real context then we have much bigger problems. Primary reason to include this
         *         additional allowed sender is because the owner address can be changed dynamically
         *         and we do not want clients to have to keep track of the current owner in order to
         *         make an eth_call that doesn't trigger the proxied contract.
         */
        // slither-disable-next-line incorrect-modifier
        modifier proxyCallIfNotOwner() {
            if (msg.sender == _getOwner() || msg.sender == address(0)) {
                _;
            } else {
                // This WILL halt the call frame on completion.
                _doProxyCall();
            }
        }
        /**
         * @param _owner Address of the initial contract owner.
         */
        constructor(address _owner) {
            _setOwner(_owner);
        }
        // slither-disable-next-line locked-ether
        receive() external payable {
            // Proxy call by default.
            _doProxyCall();
        }
        // slither-disable-next-line locked-ether
        fallback() external payable {
            // Proxy call by default.
            _doProxyCall();
        }
        /**
         * @notice Sets the code that should be running behind this proxy.
         *
         *         Note: This scheme is a bit different from the standard proxy scheme where one would
         *         typically deploy the code separately and then set the implementation address. We're
         *         doing it this way because it gives us a lot more freedom on the client side. Can
         *         only be triggered by the contract owner.
         *
         * @param _code New contract code to run inside this contract.
         */
        function setCode(bytes memory _code) external proxyCallIfNotOwner {
            // Get the code hash of the current implementation.
            address implementation = _getImplementation();
            // If the code hash matches the new implementation then we return early.
            if (keccak256(_code) == _getAccountCodeHash(implementation)) {
                return;
            }
            // Create the deploycode by appending the magic prefix.
            bytes memory deploycode = abi.encodePacked(DEPLOY_CODE_PREFIX, _code);
            // Deploy the code and set the new implementation address.
            address newImplementation;
            assembly {
                newImplementation := create(0x0, add(deploycode, 0x20), mload(deploycode))
            }
            // Check that the code was actually deployed correctly. I'm not sure if you can ever
            // actually fail this check. Should only happen if the contract creation from above runs
            // out of gas but this parent execution thread does NOT run out of gas. Seems like we
            // should be doing this check anyway though.
            require(
                _getAccountCodeHash(newImplementation) == keccak256(_code),
                "L1ChugSplashProxy: code was not correctly deployed"
            );
            _setImplementation(newImplementation);
        }
        /**
         * @notice Modifies some storage slot within the proxy contract. Gives us a lot of power to
         *         perform upgrades in a more transparent way. Only callable by the owner.
         *
         * @param _key   Storage key to modify.
         * @param _value New value for the storage key.
         */
        function setStorage(bytes32 _key, bytes32 _value) external proxyCallIfNotOwner {
            assembly {
                sstore(_key, _value)
            }
        }
        /**
         * @notice Changes the owner of the proxy contract. Only callable by the owner.
         *
         * @param _owner New owner of the proxy contract.
         */
        function setOwner(address _owner) external proxyCallIfNotOwner {
            _setOwner(_owner);
        }
        /**
         * @notice Queries the owner of the proxy contract. Can only be called by the owner OR by
         *         making an eth_call and setting the "from" address to address(0).
         *
         * @return Owner address.
         */
        function getOwner() external proxyCallIfNotOwner returns (address) {
            return _getOwner();
        }
        /**
         * @notice Queries the implementation address. Can only be called by the owner OR by making an
         *         eth_call and setting the "from" address to address(0).
         *
         * @return Implementation address.
         */
        function getImplementation() external proxyCallIfNotOwner returns (address) {
            return _getImplementation();
        }
        /**
         * @notice Sets the implementation address.
         *
         * @param _implementation New implementation address.
         */
        function _setImplementation(address _implementation) internal {
            assembly {
                sstore(IMPLEMENTATION_KEY, _implementation)
            }
        }
        /**
         * @notice Changes the owner of the proxy contract.
         *
         * @param _owner New owner of the proxy contract.
         */
        function _setOwner(address _owner) internal {
            assembly {
                sstore(OWNER_KEY, _owner)
            }
        }
        /**
         * @notice Performs the proxy call via a delegatecall.
         */
        function _doProxyCall() internal onlyWhenNotPaused {
            address implementation = _getImplementation();
            require(implementation != address(0), "L1ChugSplashProxy: implementation is not set yet");
            assembly {
                // Copy calldata into memory at 0x0....calldatasize.
                calldatacopy(0x0, 0x0, calldatasize())
                // Perform the delegatecall, make sure to pass all available gas.
                let success := delegatecall(gas(), implementation, 0x0, calldatasize(), 0x0, 0x0)
                // Copy returndata into memory at 0x0....returndatasize. Note that this *will*
                // overwrite the calldata that we just copied into memory but that doesn't really
                // matter because we'll be returning in a second anyway.
                returndatacopy(0x0, 0x0, returndatasize())
                // Success == 0 means a revert. We'll revert too and pass the data up.
                if iszero(success) {
                    revert(0x0, returndatasize())
                }
                // Otherwise we'll just return and pass the data up.
                return(0x0, returndatasize())
            }
        }
        /**
         * @notice Queries the implementation address.
         *
         * @return Implementation address.
         */
        function _getImplementation() internal view returns (address) {
            address implementation;
            assembly {
                implementation := sload(IMPLEMENTATION_KEY)
            }
            return implementation;
        }
        /**
         * @notice Queries the owner of the proxy contract.
         *
         * @return Owner address.
         */
        function _getOwner() internal view returns (address) {
            address owner;
            assembly {
                owner := sload(OWNER_KEY)
            }
            return owner;
        }
        /**
         * @notice Gets the code hash for a given account.
         *
         * @param _account Address of the account to get a code hash for.
         *
         * @return Code hash for the account.
         */
        function _getAccountCodeHash(address _account) internal view returns (bytes32) {
            bytes32 codeHash;
            assembly {
                codeHash := extcodehash(_account)
            }
            return codeHash;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.15;
    /**
     * @title Proxy
     * @notice Proxy is a transparent proxy that passes through the call if the caller is the owner or
     *         if the caller is address(0), meaning that the call originated from an off-chain
     *         simulation.
     */
    contract Proxy {
        /**
         * @notice The storage slot that holds the address of the implementation.
         *         bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
         */
        bytes32 internal constant IMPLEMENTATION_KEY =
            0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
        /**
         * @notice The storage slot that holds the address of the owner.
         *         bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
         */
        bytes32 internal constant OWNER_KEY =
            0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
        /**
         * @notice An event that is emitted each time the implementation is changed. This event is part
         *         of the EIP-1967 specification.
         *
         * @param implementation The address of the implementation contract
         */
        event Upgraded(address indexed implementation);
        /**
         * @notice An event that is emitted each time the owner is upgraded. This event is part of the
         *         EIP-1967 specification.
         *
         * @param previousAdmin The previous owner of the contract
         * @param newAdmin      The new owner of the contract
         */
        event AdminChanged(address previousAdmin, address newAdmin);
        /**
         * @notice A modifier that reverts if not called by the owner or by address(0) to allow
         *         eth_call to interact with this proxy without needing to use low-level storage
         *         inspection. We assume that nobody is able to trigger calls from address(0) during
         *         normal EVM execution.
         */
        modifier proxyCallIfNotAdmin() {
            if (msg.sender == _getAdmin() || msg.sender == address(0)) {
                _;
            } else {
                // This WILL halt the call frame on completion.
                _doProxyCall();
            }
        }
        /**
         * @notice Sets the initial admin during contract deployment. Admin address is stored at the
         *         EIP-1967 admin storage slot so that accidental storage collision with the
         *         implementation is not possible.
         *
         * @param _admin Address of the initial contract admin. Admin as the ability to access the
         *               transparent proxy interface.
         */
        constructor(address _admin) {
            _changeAdmin(_admin);
        }
        // slither-disable-next-line locked-ether
        receive() external payable {
            // Proxy call by default.
            _doProxyCall();
        }
        // slither-disable-next-line locked-ether
        fallback() external payable {
            // Proxy call by default.
            _doProxyCall();
        }
        /**
         * @notice Set the implementation contract address. The code at the given address will execute
         *         when this contract is called.
         *
         * @param _implementation Address of the implementation contract.
         */
        function upgradeTo(address _implementation) public virtual proxyCallIfNotAdmin {
            _setImplementation(_implementation);
        }
        /**
         * @notice Set the implementation and call a function in a single transaction. Useful to ensure
         *         atomic execution of initialization-based upgrades.
         *
         * @param _implementation Address of the implementation contract.
         * @param _data           Calldata to delegatecall the new implementation with.
         */
        function upgradeToAndCall(address _implementation, bytes calldata _data)
            public
            payable
            virtual
            proxyCallIfNotAdmin
            returns (bytes memory)
        {
            _setImplementation(_implementation);
            (bool success, bytes memory returndata) = _implementation.delegatecall(_data);
            require(success, "Proxy: delegatecall to new implementation contract failed");
            return returndata;
        }
        /**
         * @notice Changes the owner of the proxy contract. Only callable by the owner.
         *
         * @param _admin New owner of the proxy contract.
         */
        function changeAdmin(address _admin) public virtual proxyCallIfNotAdmin {
            _changeAdmin(_admin);
        }
        /**
         * @notice Gets the owner of the proxy contract.
         *
         * @return Owner address.
         */
        function admin() public virtual proxyCallIfNotAdmin returns (address) {
            return _getAdmin();
        }
        /**
         * @notice Queries the implementation address.
         *
         * @return Implementation address.
         */
        function implementation() public virtual proxyCallIfNotAdmin returns (address) {
            return _getImplementation();
        }
        /**
         * @notice Sets the implementation address.
         *
         * @param _implementation New implementation address.
         */
        function _setImplementation(address _implementation) internal {
            assembly {
                sstore(IMPLEMENTATION_KEY, _implementation)
            }
            emit Upgraded(_implementation);
        }
        /**
         * @notice Changes the owner of the proxy contract.
         *
         * @param _admin New owner of the proxy contract.
         */
        function _changeAdmin(address _admin) internal {
            address previous = _getAdmin();
            assembly {
                sstore(OWNER_KEY, _admin)
            }
            emit AdminChanged(previous, _admin);
        }
        /**
         * @notice Performs the proxy call via a delegatecall.
         */
        function _doProxyCall() internal {
            address impl = _getImplementation();
            require(impl != address(0), "Proxy: implementation not initialized");
            assembly {
                // Copy calldata into memory at 0x0....calldatasize.
                calldatacopy(0x0, 0x0, calldatasize())
                // Perform the delegatecall, make sure to pass all available gas.
                let success := delegatecall(gas(), impl, 0x0, calldatasize(), 0x0, 0x0)
                // Copy returndata into memory at 0x0....returndatasize. Note that this *will*
                // overwrite the calldata that we just copied into memory but that doesn't really
                // matter because we'll be returning in a second anyway.
                returndatacopy(0x0, 0x0, returndatasize())
                // Success == 0 means a revert. We'll revert too and pass the data up.
                if iszero(success) {
                    revert(0x0, returndatasize())
                }
                // Otherwise we'll just return and pass the data up.
                return(0x0, returndatasize())
            }
        }
        /**
         * @notice Queries the implementation address.
         *
         * @return Implementation address.
         */
        function _getImplementation() internal view returns (address) {
            address impl;
            assembly {
                impl := sload(IMPLEMENTATION_KEY)
            }
            return impl;
        }
        /**
         * @notice Queries the owner of the proxy contract.
         *
         * @return Owner address.
         */
        function _getAdmin() internal view returns (address) {
            address owner;
            assembly {
                owner := sload(OWNER_KEY)
            }
            return owner;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.15;
    import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
    import { Proxy } from "./Proxy.sol";
    import { AddressManager } from "../legacy/AddressManager.sol";
    import { L1ChugSplashProxy } from "../legacy/L1ChugSplashProxy.sol";
    /**
     * @title IStaticERC1967Proxy
     * @notice IStaticERC1967Proxy is a static version of the ERC1967 proxy interface.
     */
    interface IStaticERC1967Proxy {
        function implementation() external view returns (address);
        function admin() external view returns (address);
    }
    /**
     * @title IStaticL1ChugSplashProxy
     * @notice IStaticL1ChugSplashProxy is a static version of the ChugSplash proxy interface.
     */
    interface IStaticL1ChugSplashProxy {
        function getImplementation() external view returns (address);
        function getOwner() external view returns (address);
    }
    /**
     * @title ProxyAdmin
     * @notice This is an auxiliary contract meant to be assigned as the admin of an ERC1967 Proxy,
     *         based on the OpenZeppelin implementation. It has backwards compatibility logic to work
     *         with the various types of proxies that have been deployed by Optimism in the past.
     */
    contract ProxyAdmin is Ownable {
        /**
         * @notice The proxy types that the ProxyAdmin can manage.
         *
         * @custom:value ERC1967    Represents an ERC1967 compliant transparent proxy interface.
         * @custom:value CHUGSPLASH Represents the Chugsplash proxy interface (legacy).
         * @custom:value RESOLVED   Represents the ResolvedDelegate proxy (legacy).
         */
        enum ProxyType {
            ERC1967,
            CHUGSPLASH,
            RESOLVED
        }
        /**
         * @notice A mapping of proxy types, used for backwards compatibility.
         */
        mapping(address => ProxyType) public proxyType;
        /**
         * @notice A reverse mapping of addresses to names held in the AddressManager. This must be
         *         manually kept up to date with changes in the AddressManager for this contract
         *         to be able to work as an admin for the ResolvedDelegateProxy type.
         */
        mapping(address => string) public implementationName;
        /**
         * @notice The address of the address manager, this is required to manage the
         *         ResolvedDelegateProxy type.
         */
        AddressManager public addressManager;
        /**
         * @notice A legacy upgrading indicator used by the old Chugsplash Proxy.
         */
        bool internal upgrading;
        /**
         * @param _owner Address of the initial owner of this contract.
         */
        constructor(address _owner) Ownable() {
            _transferOwnership(_owner);
        }
        /**
         * @notice Sets the proxy type for a given address. Only required for non-standard (legacy)
         *         proxy types.
         *
         * @param _address Address of the proxy.
         * @param _type    Type of the proxy.
         */
        function setProxyType(address _address, ProxyType _type) external onlyOwner {
            proxyType[_address] = _type;
        }
        /**
         * @notice Sets the implementation name for a given address. Only required for
         *         ResolvedDelegateProxy type proxies that have an implementation name.
         *
         * @param _address Address of the ResolvedDelegateProxy.
         * @param _name    Name of the implementation for the proxy.
         */
        function setImplementationName(address _address, string memory _name) external onlyOwner {
            implementationName[_address] = _name;
        }
        /**
         * @notice Set the address of the AddressManager. This is required to manage legacy
         *         ResolvedDelegateProxy type proxy contracts.
         *
         * @param _address Address of the AddressManager.
         */
        function setAddressManager(AddressManager _address) external onlyOwner {
            addressManager = _address;
        }
        /**
         * @custom:legacy
         * @notice Set an address in the address manager. Since only the owner of the AddressManager
         *         can directly modify addresses and the ProxyAdmin will own the AddressManager, this
         *         gives the owner of the ProxyAdmin the ability to modify addresses directly.
         *
         * @param _name    Name to set within the AddressManager.
         * @param _address Address to attach to the given name.
         */
        function setAddress(string memory _name, address _address) external onlyOwner {
            addressManager.setAddress(_name, _address);
        }
        /**
         * @custom:legacy
         * @notice Set the upgrading status for the Chugsplash proxy type.
         *
         * @param _upgrading Whether or not the system is upgrading.
         */
        function setUpgrading(bool _upgrading) external onlyOwner {
            upgrading = _upgrading;
        }
        /**
         * @custom:legacy
         * @notice Legacy function used to tell ChugSplashProxy contracts if an upgrade is happening.
         *
         * @return Whether or not there is an upgrade going on. May not actually tell you whether an
         *         upgrade is going on, since we don't currently plan to use this variable for anything
         *         other than a legacy indicator to fix a UX bug in the ChugSplash proxy.
         */
        function isUpgrading() external view returns (bool) {
            return upgrading;
        }
        /**
         * @notice Returns the implementation of the given proxy address.
         *
         * @param _proxy Address of the proxy to get the implementation of.
         *
         * @return Address of the implementation of the proxy.
         */
        function getProxyImplementation(address _proxy) external view returns (address) {
            ProxyType ptype = proxyType[_proxy];
            if (ptype == ProxyType.ERC1967) {
                return IStaticERC1967Proxy(_proxy).implementation();
            } else if (ptype == ProxyType.CHUGSPLASH) {
                return IStaticL1ChugSplashProxy(_proxy).getImplementation();
            } else if (ptype == ProxyType.RESOLVED) {
                return addressManager.getAddress(implementationName[_proxy]);
            } else {
                revert("ProxyAdmin: unknown proxy type");
            }
        }
        /**
         * @notice Returns the admin of the given proxy address.
         *
         * @param _proxy Address of the proxy to get the admin of.
         *
         * @return Address of the admin of the proxy.
         */
        function getProxyAdmin(address payable _proxy) external view returns (address) {
            ProxyType ptype = proxyType[_proxy];
            if (ptype == ProxyType.ERC1967) {
                return IStaticERC1967Proxy(_proxy).admin();
            } else if (ptype == ProxyType.CHUGSPLASH) {
                return IStaticL1ChugSplashProxy(_proxy).getOwner();
            } else if (ptype == ProxyType.RESOLVED) {
                return addressManager.owner();
            } else {
                revert("ProxyAdmin: unknown proxy type");
            }
        }
        /**
         * @notice Updates the admin of the given proxy address.
         *
         * @param _proxy    Address of the proxy to update.
         * @param _newAdmin Address of the new proxy admin.
         */
        function changeProxyAdmin(address payable _proxy, address _newAdmin) external onlyOwner {
            ProxyType ptype = proxyType[_proxy];
            if (ptype == ProxyType.ERC1967) {
                Proxy(_proxy).changeAdmin(_newAdmin);
            } else if (ptype == ProxyType.CHUGSPLASH) {
                L1ChugSplashProxy(_proxy).setOwner(_newAdmin);
            } else if (ptype == ProxyType.RESOLVED) {
                addressManager.transferOwnership(_newAdmin);
            } else {
                revert("ProxyAdmin: unknown proxy type");
            }
        }
        /**
         * @notice Changes a proxy's implementation contract.
         *
         * @param _proxy          Address of the proxy to upgrade.
         * @param _implementation Address of the new implementation address.
         */
        function upgrade(address payable _proxy, address _implementation) public onlyOwner {
            ProxyType ptype = proxyType[_proxy];
            if (ptype == ProxyType.ERC1967) {
                Proxy(_proxy).upgradeTo(_implementation);
            } else if (ptype == ProxyType.CHUGSPLASH) {
                L1ChugSplashProxy(_proxy).setStorage(
                    // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
                    0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc,
                    bytes32(uint256(uint160(_implementation)))
                );
            } else if (ptype == ProxyType.RESOLVED) {
                string memory name = implementationName[_proxy];
                addressManager.setAddress(name, _implementation);
            } else {
                // It should not be possible to retrieve a ProxyType value which is not matched by
                // one of the previous conditions.
                assert(false);
            }
        }
        /**
         * @notice Changes a proxy's implementation contract and delegatecalls the new implementation
         *         with some given data. Useful for atomic upgrade-and-initialize calls.
         *
         * @param _proxy          Address of the proxy to upgrade.
         * @param _implementation Address of the new implementation address.
         * @param _data           Data to trigger the new implementation with.
         */
        function upgradeAndCall(
            address payable _proxy,
            address _implementation,
            bytes memory _data
        ) external payable onlyOwner {
            ProxyType ptype = proxyType[_proxy];
            if (ptype == ProxyType.ERC1967) {
                Proxy(_proxy).upgradeToAndCall{ value: msg.value }(_implementation, _data);
            } else {
                // reverts if proxy type is unknown
                upgrade(_proxy, _implementation);
                (bool success, ) = _proxy.call{ value: msg.value }(_data);
                require(success, "ProxyAdmin: call to proxy after upgrade failed");
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
    pragma solidity ^0.8.0;
    import "../utils/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract Ownable is Context {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor() {
            _transferOwnership(_msgSender());
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            _checkOwner();
            _;
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if the sender is not the owner.
         */
        function _checkOwner() internal view virtual {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            _transferOwnership(address(0));
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            _transferOwnership(newOwner);
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Internal function without access restriction.
         */
        function _transferOwnership(address newOwner) internal virtual {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }