ETH Price: $1,973.67 (+0.26%)

Transaction Decoder

Block:
24433914 at Feb-11-2026 01:45:35 PM +UTC
Transaction Fee:
0.0016046780446858 ETH $3.17
Gas Used:
313,180 Gas / 5.12382031 Gwei

Emitted Events:

0 Proxy.0xe9512d49448b580f3d29031e9243ee81bc8789a93d6f04ec8f03b694d623637b( 0xe9512d49448b580f3d29031e9243ee81bc8789a93d6f04ec8f03b694d623637b, 0x000000000000000000000000beb5fc579115071764c7423a4f12edde41f106ed, 0000000000000000000000000000000000000000000000d6b9eae1b8fa440000 )
1 L1ChugSplashProxy.0x2ac69ee804d9a7a0984249f508dfab7cb2534b465b6ce1580f99a38ba9c5e631( 0x2ac69ee804d9a7a0984249f508dfab7cb2534b465b6ce1580f99a38ba9c5e631, 0x0000000000000000000000006a9c2449c32779f89d0ccafd746152e237c1bdf2, 0x000000000000000000000000f30ba13e4b04ce5dc4d254ae5fa95477800f0eb0, 0000000000000000000000000000000000000000000000d6b9eae1b8fa440000, 0000000000000000000000000000000000000000000000000000000000000040, 0000000000000000000000000000000000000000000000000000000000000000 )
2 L1ChugSplashProxy.0x31b2166ff604fc5672ea5df08a78081d2bc6d746cadce880747f3643d819e83d( 0x31b2166ff604fc5672ea5df08a78081d2bc6d746cadce880747f3643d819e83d, 0x0000000000000000000000006a9c2449c32779f89d0ccafd746152e237c1bdf2, 0x000000000000000000000000f30ba13e4b04ce5dc4d254ae5fa95477800f0eb0, 0000000000000000000000000000000000000000000000d6b9eae1b8fa440000, 0000000000000000000000000000000000000000000000000000000000000040, 0000000000000000000000000000000000000000000000000000000000000000 )
3 Lib_ResolvedDelegateProxy.0x4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c( 0x4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c, 0xf9836ec66f7a3af0d8e6e3b55c937ddc0fb179579a522a0d8a37700f9a1112c9 )
4 Proxy.0xdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b( 0xdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b, 0xe3c62750edc799eb98e5044d165ae3c735bb3f08236a908b116cd709f7e39362, 0000000000000000000000000000000000000000000000000000000000000001 )

Account State Difference:

  Address   Before After State Difference Code
0x25ace71c...4F7ab5fA1
(Optimism: Proxy OVM L1 Cross Domain Messenger)
0x322b47Ff...71b294D43
(Optimism: ETHLockbox)
205,967.60348131187165191 Eth202,006.60348131187165191 Eth3,961
0x6A9C2449...237c1BDf2
0.450499900686846559 Eth
Nonce: 32
0.448895222642160759 Eth
Nonce: 33
0.0016046780446858
0xbEb5Fc57...e41f106Ed
(Optimism: Portal)
(BuilderNet)
61.705400552603987919 Eth61.706966452603987919 Eth0.0015659
0xf30ba13e...7800F0EB0
(Kraken: Hot Wallet 2)
93,835.094052224651816956 Eth97,796.094052224651816956 Eth3,961

Execution Trace

Proxy.8c3152e9( )
  • 0x97cebbf8959e2a5476fbe9b98a21806ec234609b.8c3152e9( )
    • Proxy.STATICCALL( )
      • 0xd392c27b84b1ca776528f2704bc67b82a62132d2.DELEGATECALL( )
        • Proxy.STATICCALL( )
          • 0x97cebbf8959e2a5476fbe9b98a21806ec234609b.DELEGATECALL( )
          • Proxy.2e48152c( )
            • 0xb08cc720f511062537ca78bdb0ae691f04f5a957.2e48152c( )
            • Proxy.2e48152c( )
              • 0xb08cc720f511062537ca78bdb0ae691f04f5a957.2e48152c( )
              • Proxy.47af267b( )
                • 0xd392c27b84b1ca776528f2704bc67b82a62132d2.47af267b( )
                • 0x01094dbc3708c5b7b3fa0807732ae0408b3f8982.STATICCALL( )
                  • 0x478c26109b169a840d61e95b19512ff0b5f19c87.cf09e0d0( )
                  • Proxy.6c4f4467( )
                    • 0x36398155cd17cfe804f69b233edda800dd4d5aa5.6c4f4467( )
                      • 0x01094dbc3708c5b7b3fa0807732ae0408b3f8982.STATICCALL( )
                        • 0x478c26109b169a840d61e95b19512ff0b5f19c87.fa24f743( )
                        • Proxy.5f0150cb( )
                          • 0xc040f392e52cb6970ca8e110c280fe24e07c5e2c.5f0150cb( )
                          • 0x01094dbc3708c5b7b3fa0807732ae0408b3f8982.STATICCALL( )
                            • 0x478c26109b169a840d61e95b19512ff0b5f19c87.5c0cba33( )
                            • 0x01094dbc3708c5b7b3fa0807732ae0408b3f8982.STATICCALL( )
                              • 0x478c26109b169a840d61e95b19512ff0b5f19c87.cf09e0d0( )
                              • Proxy.STATICCALL( )
                                • 0xd392c27b84b1ca776528f2704bc67b82a62132d2.DELEGATECALL( )
                                  • Proxy.STATICCALL( )
                                  • Proxy.2e48152c( )
                                  • Proxy.2e48152c( )
                                  • 0x01094dbc3708c5b7b3fa0807732ae0408b3f8982.STATICCALL( )
                                    • 0x478c26109b169a840d61e95b19512ff0b5f19c87.250e69bd( )
                                    • 0x01094dbc3708c5b7b3fa0807732ae0408b3f8982.STATICCALL( )
                                      • 0x478c26109b169a840d61e95b19512ff0b5f19c87.19effeb4( )
                                      • 0x01094dbc3708c5b7b3fa0807732ae0408b3f8982.STATICCALL( )
                                        • 0x478c26109b169a840d61e95b19512ff0b5f19c87.200d2ed2( )
                                        • 0x01094dbc3708c5b7b3fa0807732ae0408b3f8982.STATICCALL( )
                                          • 0x478c26109b169a840d61e95b19512ff0b5f19c87.19effeb4( )
                                          • 0x01094dbc3708c5b7b3fa0807732ae0408b3f8982.STATICCALL( )
                                            • 0x478c26109b169a840d61e95b19512ff0b5f19c87.200d2ed2( )
                                            • Proxy.47af267b( )
                                              • 0xd392c27b84b1ca776528f2704bc67b82a62132d2.47af267b( )
                                              • Proxy.8d445bd0( )
                                                • 0x784d2f03593a42a6e4676a012762f18775ecbbe6.8d445bd0( )
                                                  • Proxy.STATICCALL( )
                                                    • 0xd392c27b84b1ca776528f2704bc67b82a62132d2.DELEGATECALL( )
                                                      • Proxy.STATICCALL( )
                                                      • Proxy.2e48152c( )
                                                      • Proxy.2e48152c( )
                                                      • Proxy.STATICCALL( )
                                                        • 0x97cebbf8959e2a5476fbe9b98a21806ec234609b.DELEGATECALL( )
                                                        • ETH 3961 Proxy.CALL( )
                                                          • ETH 3961 0x97cebbf8959e2a5476fbe9b98a21806ec234609b.DELEGATECALL( )
                                                          • ETH 3961 Lib_ResolvedDelegateProxy.d764ad0b( )
                                                            • Lib_AddressManager.getAddress( _name=OVM_L1CrossDomainMessenger ) => ( 0xb686F13AfF1e427a1f993F29ab0F2E7383729FE0 )
                                                            • ETH 3961 0xb686f13aff1e427a1f993f29ab0f2e7383729fe0.d764ad0b( )
                                                              • Proxy.STATICCALL( )
                                                                • 0xd392c27b84b1ca776528f2704bc67b82a62132d2.DELEGATECALL( )
                                                                  • Proxy.STATICCALL( )
                                                                  • Proxy.2e48152c( )
                                                                  • Proxy.2e48152c( )
                                                                  • Proxy.STATICCALL( )
                                                                    • 0x97cebbf8959e2a5476fbe9b98a21806ec234609b.DELEGATECALL( )
                                                                    • ETH 3961 L1ChugSplashProxy.1635f5fd( )
                                                                      • ProxyAdmin.STATICCALL( )
                                                                      • ETH 3961 0x61525eaacddb97d9184afc205827e6a4fd0bf62a.1635f5fd( )
                                                                        • Lib_ResolvedDelegateProxy.STATICCALL( )
                                                                        • Proxy.STATICCALL( )
                                                                        • ETH 3961 Kraken: Hot Wallet 2.CALL( )
                                                                        • Proxy.47af267b( )
                                                                          • 0xd392c27b84b1ca776528f2704bc67b82a62132d2.47af267b( )
                                                                            File 1 of 10: Proxy
                                                                            // 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;
                                                                                }
                                                                            }
                                                                            

                                                                            File 2 of 10: Proxy
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { Constants } from "../libraries/Constants.sol";
                                                                            /// @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 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 {
                                                                                    bytes32 proxyImplementation = Constants.PROXY_IMPLEMENTATION_ADDRESS;
                                                                                    assembly {
                                                                                        sstore(proxyImplementation, _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();
                                                                                    bytes32 proxyOwner = Constants.PROXY_OWNER_ADDRESS;
                                                                                    assembly {
                                                                                        sstore(proxyOwner, _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;
                                                                                    bytes32 proxyImplementation = Constants.PROXY_IMPLEMENTATION_ADDRESS;
                                                                                    assembly {
                                                                                        impl := sload(proxyImplementation)
                                                                                    }
                                                                                    return impl;
                                                                                }
                                                                                /// @notice Queries the owner of the proxy contract.
                                                                                /// @return Owner address.
                                                                                function _getAdmin() internal view returns (address) {
                                                                                    address owner;
                                                                                    bytes32 proxyOwner = Constants.PROXY_OWNER_ADDRESS;
                                                                                    assembly {
                                                                                        owner := sload(proxyOwner)
                                                                                    }
                                                                                    return owner;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity ^0.8.0;
                                                                            import { ResourceMetering } from "../L1/ResourceMetering.sol";
                                                                            /// @title Constants
                                                                            /// @notice Constants is a library for storing constants. Simple! Don't put everything in here, just
                                                                            ///         the stuff used in multiple contracts. Constants that only apply to a single contract
                                                                            ///         should be defined in that contract instead.
                                                                            library Constants {
                                                                                /// @notice Special address to be used as the tx origin for gas estimation calls in the
                                                                                ///         OptimismPortal and CrossDomainMessenger calls. You only need to use this address if
                                                                                ///         the minimum gas limit specified by the user is not actually enough to execute the
                                                                                ///         given message and you're attempting to estimate the actual necessary gas limit. We
                                                                                ///         use address(1) because it's the ecrecover precompile and therefore guaranteed to
                                                                                ///         never have any code on any EVM chain.
                                                                                address internal constant ESTIMATION_ADDRESS = address(1);
                                                                                /// @notice Value used for the L2 sender storage slot in both the OptimismPortal and the
                                                                                ///         CrossDomainMessenger contracts before an actual sender is set. This value is
                                                                                ///         non-zero to reduce the gas cost of message passing transactions.
                                                                                address internal constant DEFAULT_L2_SENDER = 0x000000000000000000000000000000000000dEaD;
                                                                                /// @notice The storage slot that holds the address of a proxy implementation.
                                                                                /// @dev `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)`
                                                                                bytes32 internal constant PROXY_IMPLEMENTATION_ADDRESS =
                                                                                    0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                                                                                /// @notice The storage slot that holds the address of the owner.
                                                                                /// @dev `bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)`
                                                                                bytes32 internal constant PROXY_OWNER_ADDRESS = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                                                                                /// @notice Returns the default values for the ResourceConfig. These are the recommended values
                                                                                ///         for a production network.
                                                                                function DEFAULT_RESOURCE_CONFIG() internal pure returns (ResourceMetering.ResourceConfig memory) {
                                                                                    ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({
                                                                                        maxResourceLimit: 20_000_000,
                                                                                        elasticityMultiplier: 10,
                                                                                        baseFeeMaxChangeDenominator: 8,
                                                                                        minimumBaseFee: 1 gwei,
                                                                                        systemTxMaxGas: 1_000_000,
                                                                                        maximumBaseFee: type(uint128).max
                                                                                    });
                                                                                    return config;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
                                                                            import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
                                                                            import { Burn } from "../libraries/Burn.sol";
                                                                            import { Arithmetic } from "../libraries/Arithmetic.sol";
                                                                            /// @custom:upgradeable
                                                                            /// @title ResourceMetering
                                                                            /// @notice ResourceMetering implements an EIP-1559 style resource metering system where pricing
                                                                            ///         updates automatically based on current demand.
                                                                            abstract contract ResourceMetering is Initializable {
                                                                                /// @notice Represents the various parameters that control the way in which resources are
                                                                                ///         metered. Corresponds to the EIP-1559 resource metering system.
                                                                                /// @custom:field prevBaseFee   Base fee from the previous block(s).
                                                                                /// @custom:field prevBoughtGas Amount of gas bought so far in the current block.
                                                                                /// @custom:field prevBlockNum  Last block number that the base fee was updated.
                                                                                struct ResourceParams {
                                                                                    uint128 prevBaseFee;
                                                                                    uint64 prevBoughtGas;
                                                                                    uint64 prevBlockNum;
                                                                                }
                                                                                /// @notice Represents the configuration for the EIP-1559 based curve for the deposit gas
                                                                                ///         market. These values should be set with care as it is possible to set them in
                                                                                ///         a way that breaks the deposit gas market. The target resource limit is defined as
                                                                                ///         maxResourceLimit / elasticityMultiplier. This struct was designed to fit within a
                                                                                ///         single word. There is additional space for additions in the future.
                                                                                /// @custom:field maxResourceLimit             Represents the maximum amount of deposit gas that
                                                                                ///                                            can be purchased per block.
                                                                                /// @custom:field elasticityMultiplier         Determines the target resource limit along with
                                                                                ///                                            the resource limit.
                                                                                /// @custom:field baseFeeMaxChangeDenominator  Determines max change on fee per block.
                                                                                /// @custom:field minimumBaseFee               The min deposit base fee, it is clamped to this
                                                                                ///                                            value.
                                                                                /// @custom:field systemTxMaxGas               The amount of gas supplied to the system
                                                                                ///                                            transaction. This should be set to the same
                                                                                ///                                            number that the op-node sets as the gas limit
                                                                                ///                                            for the system transaction.
                                                                                /// @custom:field maximumBaseFee               The max deposit base fee, it is clamped to this
                                                                                ///                                            value.
                                                                                struct ResourceConfig {
                                                                                    uint32 maxResourceLimit;
                                                                                    uint8 elasticityMultiplier;
                                                                                    uint8 baseFeeMaxChangeDenominator;
                                                                                    uint32 minimumBaseFee;
                                                                                    uint32 systemTxMaxGas;
                                                                                    uint128 maximumBaseFee;
                                                                                }
                                                                                /// @notice EIP-1559 style gas parameters.
                                                                                ResourceParams public params;
                                                                                /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades.
                                                                                uint256[48] private __gap;
                                                                                /// @notice Meters access to a function based an amount of a requested resource.
                                                                                /// @param _amount Amount of the resource requested.
                                                                                modifier metered(uint64 _amount) {
                                                                                    // Record initial gas amount so we can refund for it later.
                                                                                    uint256 initialGas = gasleft();
                                                                                    // Run the underlying function.
                                                                                    _;
                                                                                    // Run the metering function.
                                                                                    _metered(_amount, initialGas);
                                                                                }
                                                                                /// @notice An internal function that holds all of the logic for metering a resource.
                                                                                /// @param _amount     Amount of the resource requested.
                                                                                /// @param _initialGas The amount of gas before any modifier execution.
                                                                                function _metered(uint64 _amount, uint256 _initialGas) internal {
                                                                                    // Update block number and base fee if necessary.
                                                                                    uint256 blockDiff = block.number - params.prevBlockNum;
                                                                                    ResourceConfig memory config = _resourceConfig();
                                                                                    int256 targetResourceLimit =
                                                                                        int256(uint256(config.maxResourceLimit)) / int256(uint256(config.elasticityMultiplier));
                                                                                    if (blockDiff > 0) {
                                                                                        // Handle updating EIP-1559 style gas parameters. We use EIP-1559 to restrict the rate
                                                                                        // at which deposits can be created and therefore limit the potential for deposits to
                                                                                        // spam the L2 system. Fee scheme is very similar to EIP-1559 with minor changes.
                                                                                        int256 gasUsedDelta = int256(uint256(params.prevBoughtGas)) - targetResourceLimit;
                                                                                        int256 baseFeeDelta = (int256(uint256(params.prevBaseFee)) * gasUsedDelta)
                                                                                            / (targetResourceLimit * int256(uint256(config.baseFeeMaxChangeDenominator)));
                                                                                        // Update base fee by adding the base fee delta and clamp the resulting value between
                                                                                        // min and max.
                                                                                        int256 newBaseFee = Arithmetic.clamp({
                                                                                            _value: int256(uint256(params.prevBaseFee)) + baseFeeDelta,
                                                                                            _min: int256(uint256(config.minimumBaseFee)),
                                                                                            _max: int256(uint256(config.maximumBaseFee))
                                                                                        });
                                                                                        // If we skipped more than one block, we also need to account for every empty block.
                                                                                        // Empty block means there was no demand for deposits in that block, so we should
                                                                                        // reflect this lack of demand in the fee.
                                                                                        if (blockDiff > 1) {
                                                                                            // Update the base fee by repeatedly applying the exponent 1-(1/change_denominator)
                                                                                            // blockDiff - 1 times. Simulates multiple empty blocks. Clamp the resulting value
                                                                                            // between min and max.
                                                                                            newBaseFee = Arithmetic.clamp({
                                                                                                _value: Arithmetic.cdexp({
                                                                                                    _coefficient: newBaseFee,
                                                                                                    _denominator: int256(uint256(config.baseFeeMaxChangeDenominator)),
                                                                                                    _exponent: int256(blockDiff - 1)
                                                                                                }),
                                                                                                _min: int256(uint256(config.minimumBaseFee)),
                                                                                                _max: int256(uint256(config.maximumBaseFee))
                                                                                            });
                                                                                        }
                                                                                        // Update new base fee, reset bought gas, and update block number.
                                                                                        params.prevBaseFee = uint128(uint256(newBaseFee));
                                                                                        params.prevBoughtGas = 0;
                                                                                        params.prevBlockNum = uint64(block.number);
                                                                                    }
                                                                                    // Make sure we can actually buy the resource amount requested by the user.
                                                                                    params.prevBoughtGas += _amount;
                                                                                    require(
                                                                                        int256(uint256(params.prevBoughtGas)) <= int256(uint256(config.maxResourceLimit)),
                                                                                        "ResourceMetering: cannot buy more gas than available gas limit"
                                                                                    );
                                                                                    // Determine the amount of ETH to be paid.
                                                                                    uint256 resourceCost = uint256(_amount) * uint256(params.prevBaseFee);
                                                                                    // We currently charge for this ETH amount as an L1 gas burn, so we convert the ETH amount
                                                                                    // into gas by dividing by the L1 base fee. We assume a minimum base fee of 1 gwei to avoid
                                                                                    // division by zero for L1s that don't support 1559 or to avoid excessive gas burns during
                                                                                    // periods of extremely low L1 demand. One-day average gas fee hasn't dipped below 1 gwei
                                                                                    // during any 1 day period in the last 5 years, so should be fine.
                                                                                    uint256 gasCost = resourceCost / Math.max(block.basefee, 1 gwei);
                                                                                    // Give the user a refund based on the amount of gas they used to do all of the work up to
                                                                                    // this point. Since we're at the end of the modifier, this should be pretty accurate. Acts
                                                                                    // effectively like a dynamic stipend (with a minimum value).
                                                                                    uint256 usedGas = _initialGas - gasleft();
                                                                                    if (gasCost > usedGas) {
                                                                                        Burn.gas(gasCost - usedGas);
                                                                                    }
                                                                                }
                                                                                /// @notice Virtual function that returns the resource config.
                                                                                ///         Contracts that inherit this contract must implement this function.
                                                                                /// @return ResourceConfig
                                                                                function _resourceConfig() internal virtual returns (ResourceConfig memory);
                                                                                /// @notice Sets initial resource parameter values.
                                                                                ///         This function must either be called by the initializer function of an upgradeable
                                                                                ///         child contract.
                                                                                // solhint-disable-next-line func-name-mixedcase
                                                                                function __ResourceMetering_init() internal onlyInitializing {
                                                                                    params = ResourceParams({ prevBaseFee: 1 gwei, prevBoughtGas: 0, prevBlockNum: uint64(block.number) });
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
                                                                            pragma solidity ^0.8.2;
                                                                            import "../../utils/Address.sol";
                                                                            /**
                                                                             * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                                                                             * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
                                                                             * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                                                                             * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                                                                             *
                                                                             * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
                                                                             * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
                                                                             * case an upgrade adds a module that needs to be initialized.
                                                                             *
                                                                             * For example:
                                                                             *
                                                                             * [.hljs-theme-light.nopadding]
                                                                             * ```
                                                                             * contract MyToken is ERC20Upgradeable {
                                                                             *     function initialize() initializer public {
                                                                             *         __ERC20_init("MyToken", "MTK");
                                                                             *     }
                                                                             * }
                                                                             * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
                                                                             *     function initializeV2() reinitializer(2) public {
                                                                             *         __ERC20Permit_init("MyToken");
                                                                             *     }
                                                                             * }
                                                                             * ```
                                                                             *
                                                                             * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                                                                             * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                                                                             *
                                                                             * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                                                                             * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                                                                             *
                                                                             * [CAUTION]
                                                                             * ====
                                                                             * Avoid leaving a contract uninitialized.
                                                                             *
                                                                             * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                                                                             * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
                                                                             * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
                                                                             *
                                                                             * [.hljs-theme-light.nopadding]
                                                                             * ```
                                                                             * /// @custom:oz-upgrades-unsafe-allow constructor
                                                                             * constructor() {
                                                                             *     _disableInitializers();
                                                                             * }
                                                                             * ```
                                                                             * ====
                                                                             */
                                                                            abstract contract Initializable {
                                                                                /**
                                                                                 * @dev Indicates that the contract has been initialized.
                                                                                 * @custom:oz-retyped-from bool
                                                                                 */
                                                                                uint8 private _initialized;
                                                                                /**
                                                                                 * @dev Indicates that the contract is in the process of being initialized.
                                                                                 */
                                                                                bool private _initializing;
                                                                                /**
                                                                                 * @dev Triggered when the contract has been initialized or reinitialized.
                                                                                 */
                                                                                event Initialized(uint8 version);
                                                                                /**
                                                                                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                                                                                 * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
                                                                                 */
                                                                                modifier initializer() {
                                                                                    bool isTopLevelCall = !_initializing;
                                                                                    require(
                                                                                        (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
                                                                                        "Initializable: contract is already initialized"
                                                                                    );
                                                                                    _initialized = 1;
                                                                                    if (isTopLevelCall) {
                                                                                        _initializing = true;
                                                                                    }
                                                                                    _;
                                                                                    if (isTopLevelCall) {
                                                                                        _initializing = false;
                                                                                        emit Initialized(1);
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                                                                                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                                                                                 * used to initialize parent contracts.
                                                                                 *
                                                                                 * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
                                                                                 * initialization step. This is essential to configure modules that are added through upgrades and that require
                                                                                 * initialization.
                                                                                 *
                                                                                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                                                                                 * a contract, executing them in the right order is up to the developer or operator.
                                                                                 */
                                                                                modifier reinitializer(uint8 version) {
                                                                                    require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                                                                                    _initialized = version;
                                                                                    _initializing = true;
                                                                                    _;
                                                                                    _initializing = false;
                                                                                    emit Initialized(version);
                                                                                }
                                                                                /**
                                                                                 * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                                                                                 * {initializer} and {reinitializer} modifiers, directly or indirectly.
                                                                                 */
                                                                                modifier onlyInitializing() {
                                                                                    require(_initializing, "Initializable: contract is not initializing");
                                                                                    _;
                                                                                }
                                                                                /**
                                                                                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                                                                                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                                                                                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                                                                                 * through proxies.
                                                                                 */
                                                                                function _disableInitializers() internal virtual {
                                                                                    require(!_initializing, "Initializable: contract is initializing");
                                                                                    if (_initialized < type(uint8).max) {
                                                                                        _initialized = type(uint8).max;
                                                                                        emit Initialized(type(uint8).max);
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
                                                                            pragma solidity ^0.8.0;
                                                                            /**
                                                                             * @dev Standard math utilities missing in the Solidity language.
                                                                             */
                                                                            library Math {
                                                                                enum Rounding {
                                                                                    Down, // Toward negative infinity
                                                                                    Up, // Toward infinity
                                                                                    Zero // Toward zero
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the largest of two numbers.
                                                                                 */
                                                                                function max(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    return a >= b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the smallest of two numbers.
                                                                                 */
                                                                                function min(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    return a < b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the average of two numbers. The result is rounded towards
                                                                                 * zero.
                                                                                 */
                                                                                function average(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    // (a + b) / 2 can overflow.
                                                                                    return (a & b) + (a ^ b) / 2;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the ceiling of the division of two numbers.
                                                                                 *
                                                                                 * This differs from standard division with `/` in that it rounds up instead
                                                                                 * of rounding down.
                                                                                 */
                                                                                function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    // (a + b - 1) / b can overflow on addition, so we distribute.
                                                                                    return a == 0 ? 0 : (a - 1) / b + 1;
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
                                                                                 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
                                                                                 * with further edits by Uniswap Labs also under MIT license.
                                                                                 */
                                                                                function mulDiv(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 result) {
                                                                                    unchecked {
                                                                                        // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                                                                                        // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                                                                                        // variables such that product = prod1 * 2^256 + prod0.
                                                                                        uint256 prod0; // Least significant 256 bits of the product
                                                                                        uint256 prod1; // Most significant 256 bits of the product
                                                                                        assembly {
                                                                                            let mm := mulmod(x, y, not(0))
                                                                                            prod0 := mul(x, y)
                                                                                            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                                                                                        }
                                                                                        // Handle non-overflow cases, 256 by 256 division.
                                                                                        if (prod1 == 0) {
                                                                                            return prod0 / denominator;
                                                                                        }
                                                                                        // Make sure the result is less than 2^256. Also prevents denominator == 0.
                                                                                        require(denominator > prod1);
                                                                                        ///////////////////////////////////////////////
                                                                                        // 512 by 256 division.
                                                                                        ///////////////////////////////////////////////
                                                                                        // Make division exact by subtracting the remainder from [prod1 prod0].
                                                                                        uint256 remainder;
                                                                                        assembly {
                                                                                            // Compute remainder using mulmod.
                                                                                            remainder := mulmod(x, y, denominator)
                                                                                            // Subtract 256 bit number from 512 bit number.
                                                                                            prod1 := sub(prod1, gt(remainder, prod0))
                                                                                            prod0 := sub(prod0, remainder)
                                                                                        }
                                                                                        // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                                                                                        // See https://cs.stackexchange.com/q/138556/92363.
                                                                                        // Does not overflow because the denominator cannot be zero at this stage in the function.
                                                                                        uint256 twos = denominator & (~denominator + 1);
                                                                                        assembly {
                                                                                            // Divide denominator by twos.
                                                                                            denominator := div(denominator, twos)
                                                                                            // Divide [prod1 prod0] by twos.
                                                                                            prod0 := div(prod0, twos)
                                                                                            // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                                                                                            twos := add(div(sub(0, twos), twos), 1)
                                                                                        }
                                                                                        // Shift in bits from prod1 into prod0.
                                                                                        prod0 |= prod1 * twos;
                                                                                        // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                                                                                        // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                                                                                        // four bits. That is, denominator * inv = 1 mod 2^4.
                                                                                        uint256 inverse = (3 * denominator) ^ 2;
                                                                                        // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                                                                                        // in modular arithmetic, doubling the correct bits in each step.
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^8
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^16
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^32
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^64
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^128
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^256
                                                                                        // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                                                                                        // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                                                                                        // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                                                                                        // is no longer required.
                                                                                        result = prod0 * inverse;
                                                                                        return result;
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
                                                                                 */
                                                                                function mulDiv(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator,
                                                                                    Rounding rounding
                                                                                ) internal pure returns (uint256) {
                                                                                    uint256 result = mulDiv(x, y, denominator);
                                                                                    if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                                                                                        result += 1;
                                                                                    }
                                                                                    return result;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
                                                                                 *
                                                                                 * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
                                                                                 */
                                                                                function sqrt(uint256 a) internal pure returns (uint256) {
                                                                                    if (a == 0) {
                                                                                        return 0;
                                                                                    }
                                                                                    // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                                                                                    // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                                                                                    // `msb(a) <= a < 2*msb(a)`.
                                                                                    // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
                                                                                    // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
                                                                                    // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
                                                                                    // good first aproximation of `sqrt(a)` with at least 1 correct bit.
                                                                                    uint256 result = 1;
                                                                                    uint256 x = a;
                                                                                    if (x >> 128 > 0) {
                                                                                        x >>= 128;
                                                                                        result <<= 64;
                                                                                    }
                                                                                    if (x >> 64 > 0) {
                                                                                        x >>= 64;
                                                                                        result <<= 32;
                                                                                    }
                                                                                    if (x >> 32 > 0) {
                                                                                        x >>= 32;
                                                                                        result <<= 16;
                                                                                    }
                                                                                    if (x >> 16 > 0) {
                                                                                        x >>= 16;
                                                                                        result <<= 8;
                                                                                    }
                                                                                    if (x >> 8 > 0) {
                                                                                        x >>= 8;
                                                                                        result <<= 4;
                                                                                    }
                                                                                    if (x >> 4 > 0) {
                                                                                        x >>= 4;
                                                                                        result <<= 2;
                                                                                    }
                                                                                    if (x >> 2 > 0) {
                                                                                        result <<= 1;
                                                                                    }
                                                                                    // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                                                                                    // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                                                                                    // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                                                                                    // into the expected uint128 result.
                                                                                    unchecked {
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        return min(result, a / result);
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates sqrt(a), following the selected rounding direction.
                                                                                 */
                                                                                function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                                                                                    uint256 result = sqrt(a);
                                                                                    if (rounding == Rounding.Up && result * result < a) {
                                                                                        result += 1;
                                                                                    }
                                                                                    return result;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            /// @title Burn
                                                                            /// @notice Utilities for burning stuff.
                                                                            library Burn {
                                                                                /// @notice Burns a given amount of ETH.
                                                                                /// @param _amount Amount of ETH to burn.
                                                                                function eth(uint256 _amount) internal {
                                                                                    new Burner{ value: _amount }();
                                                                                }
                                                                                /// @notice Burns a given amount of gas.
                                                                                /// @param _amount Amount of gas to burn.
                                                                                function gas(uint256 _amount) internal view {
                                                                                    uint256 i = 0;
                                                                                    uint256 initialGas = gasleft();
                                                                                    while (initialGas - gasleft() < _amount) {
                                                                                        ++i;
                                                                                    }
                                                                                }
                                                                            }
                                                                            /// @title Burner
                                                                            /// @notice Burner self-destructs on creation and sends all ETH to itself, removing all ETH given to
                                                                            ///         the contract from the circulating supply. Self-destructing is the only way to remove ETH
                                                                            ///         from the circulating supply.
                                                                            contract Burner {
                                                                                constructor() payable {
                                                                                    selfdestruct(payable(address(this)));
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { SignedMath } from "@openzeppelin/contracts/utils/math/SignedMath.sol";
                                                                            import { FixedPointMathLib } from "@rari-capital/solmate/src/utils/FixedPointMathLib.sol";
                                                                            /// @title Arithmetic
                                                                            /// @notice Even more math than before.
                                                                            library Arithmetic {
                                                                                /// @notice Clamps a value between a minimum and maximum.
                                                                                /// @param _value The value to clamp.
                                                                                /// @param _min   The minimum value.
                                                                                /// @param _max   The maximum value.
                                                                                /// @return The clamped value.
                                                                                function clamp(int256 _value, int256 _min, int256 _max) internal pure returns (int256) {
                                                                                    return SignedMath.min(SignedMath.max(_value, _min), _max);
                                                                                }
                                                                                /// @notice (c)oefficient (d)enominator (exp)onentiation function.
                                                                                ///         Returns the result of: c * (1 - 1/d)^exp.
                                                                                /// @param _coefficient Coefficient of the function.
                                                                                /// @param _denominator Fractional denominator.
                                                                                /// @param _exponent    Power function exponent.
                                                                                /// @return Result of c * (1 - 1/d)^exp.
                                                                                function cdexp(int256 _coefficient, int256 _denominator, int256 _exponent) internal pure returns (int256) {
                                                                                    return (_coefficient * (FixedPointMathLib.powWad(1e18 - (1e18 / _denominator), _exponent * 1e18))) / 1e18;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
                                                                            pragma solidity ^0.8.1;
                                                                            /**
                                                                             * @dev Collection of functions related to the address type
                                                                             */
                                                                            library Address {
                                                                                /**
                                                                                 * @dev Returns true if `account` is a contract.
                                                                                 *
                                                                                 * [IMPORTANT]
                                                                                 * ====
                                                                                 * It is unsafe to assume that an address for which this function returns
                                                                                 * false is an externally-owned account (EOA) and not a contract.
                                                                                 *
                                                                                 * Among others, `isContract` will return false for the following
                                                                                 * types of addresses:
                                                                                 *
                                                                                 *  - an externally-owned account
                                                                                 *  - a contract in construction
                                                                                 *  - an address where a contract will be created
                                                                                 *  - an address where a contract lived, but was destroyed
                                                                                 * ====
                                                                                 *
                                                                                 * [IMPORTANT]
                                                                                 * ====
                                                                                 * You shouldn't rely on `isContract` to protect against flash loan attacks!
                                                                                 *
                                                                                 * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                                                                                 * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                                                                                 * constructor.
                                                                                 * ====
                                                                                 */
                                                                                function isContract(address account) internal view returns (bool) {
                                                                                    // This method relies on extcodesize/address.code.length, which returns 0
                                                                                    // for contracts in construction, since the code is only stored at the end
                                                                                    // of the constructor execution.
                                                                                    return account.code.length > 0;
                                                                                }
                                                                                /**
                                                                                 * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                                                                                 * `recipient`, forwarding all available gas and reverting on errors.
                                                                                 *
                                                                                 * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                                                                                 * of certain opcodes, possibly making contracts go over the 2300 gas limit
                                                                                 * imposed by `transfer`, making them unable to receive funds via
                                                                                 * `transfer`. {sendValue} removes this limitation.
                                                                                 *
                                                                                 * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                                                                                 *
                                                                                 * IMPORTANT: because control is transferred to `recipient`, care must be
                                                                                 * taken to not create reentrancy vulnerabilities. Consider using
                                                                                 * {ReentrancyGuard} or the
                                                                                 * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                                                                                 */
                                                                                function sendValue(address payable recipient, uint256 amount) internal {
                                                                                    require(address(this).balance >= amount, "Address: insufficient balance");
                                                                                    (bool success, ) = recipient.call{value: amount}("");
                                                                                    require(success, "Address: unable to send value, recipient may have reverted");
                                                                                }
                                                                                /**
                                                                                 * @dev Performs a Solidity function call using a low level `call`. A
                                                                                 * plain `call` is an unsafe replacement for a function call: use this
                                                                                 * function instead.
                                                                                 *
                                                                                 * If `target` reverts with a revert reason, it is bubbled up by this
                                                                                 * function (like regular Solidity function calls).
                                                                                 *
                                                                                 * Returns the raw returned data. To convert to the expected return value,
                                                                                 * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                                                                                 *
                                                                                 * Requirements:
                                                                                 *
                                                                                 * - `target` must be a contract.
                                                                                 * - calling `target` with `data` must not revert.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                                                                    return functionCall(target, data, "Address: low-level call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                                                                                 * `errorMessage` as a fallback revert reason when `target` reverts.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    return functionCallWithValue(target, data, 0, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but also transferring `value` wei to `target`.
                                                                                 *
                                                                                 * Requirements:
                                                                                 *
                                                                                 * - the calling contract must have an ETH balance of at least `value`.
                                                                                 * - the called Solidity function must be `payable`.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCallWithValue(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    uint256 value
                                                                                ) internal returns (bytes memory) {
                                                                                    return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                                                                                 * with `errorMessage` as a fallback revert reason when `target` reverts.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCallWithValue(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    uint256 value,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    require(address(this).balance >= value, "Address: insufficient balance for call");
                                                                                    require(isContract(target), "Address: call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but performing a static call.
                                                                                 *
                                                                                 * _Available since v3.3._
                                                                                 */
                                                                                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                                                                    return functionStaticCall(target, data, "Address: low-level static call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                                                                                 * but performing a static call.
                                                                                 *
                                                                                 * _Available since v3.3._
                                                                                 */
                                                                                function functionStaticCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal view returns (bytes memory) {
                                                                                    require(isContract(target), "Address: static call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.staticcall(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but performing a delegate call.
                                                                                 *
                                                                                 * _Available since v3.4._
                                                                                 */
                                                                                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                                                                    return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                                                                                 * but performing a delegate call.
                                                                                 *
                                                                                 * _Available since v3.4._
                                                                                 */
                                                                                function functionDelegateCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    require(isContract(target), "Address: delegate call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.delegatecall(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                                                                                 * revert reason using the provided one.
                                                                                 *
                                                                                 * _Available since v4.3._
                                                                                 */
                                                                                function verifyCallResult(
                                                                                    bool success,
                                                                                    bytes memory returndata,
                                                                                    string memory errorMessage
                                                                                ) internal pure returns (bytes memory) {
                                                                                    if (success) {
                                                                                        return returndata;
                                                                                    } else {
                                                                                        // Look for revert reason and bubble it up if present
                                                                                        if (returndata.length > 0) {
                                                                                            // The easiest way to bubble the revert reason is using memory via assembly
                                                                                            /// @solidity memory-safe-assembly
                                                                                            assembly {
                                                                                                let returndata_size := mload(returndata)
                                                                                                revert(add(32, returndata), returndata_size)
                                                                                            }
                                                                                        } else {
                                                                                            revert(errorMessage);
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.5.0) (utils/math/SignedMath.sol)
                                                                            pragma solidity ^0.8.0;
                                                                            /**
                                                                             * @dev Standard signed math utilities missing in the Solidity language.
                                                                             */
                                                                            library SignedMath {
                                                                                /**
                                                                                 * @dev Returns the largest of two signed numbers.
                                                                                 */
                                                                                function max(int256 a, int256 b) internal pure returns (int256) {
                                                                                    return a >= b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the smallest of two signed numbers.
                                                                                 */
                                                                                function min(int256 a, int256 b) internal pure returns (int256) {
                                                                                    return a < b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the average of two signed numbers without overflow.
                                                                                 * The result is rounded towards zero.
                                                                                 */
                                                                                function average(int256 a, int256 b) internal pure returns (int256) {
                                                                                    // Formula from the book "Hacker's Delight"
                                                                                    int256 x = (a & b) + ((a ^ b) >> 1);
                                                                                    return x + (int256(uint256(x) >> 255) & (a ^ b));
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the absolute unsigned value of a signed value.
                                                                                 */
                                                                                function abs(int256 n) internal pure returns (uint256) {
                                                                                    unchecked {
                                                                                        // must be unchecked in order to support `n = type(int256).min`
                                                                                        return uint256(n >= 0 ? n : -n);
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >=0.8.0;
                                                                            /// @notice Arithmetic library with operations for fixed-point numbers.
                                                                            /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
                                                                            library FixedPointMathLib {
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                SIMPLIFIED FIXED POINT OPERATIONS
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
                                                                                function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
                                                                                }
                                                                                function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
                                                                                }
                                                                                function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
                                                                                }
                                                                                function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
                                                                                }
                                                                                function powWad(int256 x, int256 y) internal pure returns (int256) {
                                                                                    // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)
                                                                                    return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0.
                                                                                }
                                                                                function expWad(int256 x) internal pure returns (int256 r) {
                                                                                    unchecked {
                                                                                        // When the result is < 0.5 we return zero. This happens when
                                                                                        // x <= floor(log(0.5e18) * 1e18) ~ -42e18
                                                                                        if (x <= -42139678854452767551) return 0;
                                                                                        // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
                                                                                        // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
                                                                                        if (x >= 135305999368893231589) revert("EXP_OVERFLOW");
                                                                                        // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
                                                                                        // for more intermediate precision and a binary basis. This base conversion
                                                                                        // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
                                                                                        x = (x << 78) / 5**18;
                                                                                        // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
                                                                                        // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
                                                                                        // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
                                                                                        int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
                                                                                        x = x - k * 54916777467707473351141471128;
                                                                                        // k is in the range [-61, 195].
                                                                                        // Evaluate using a (6, 7)-term rational approximation.
                                                                                        // p is made monic, we'll multiply by a scale factor later.
                                                                                        int256 y = x + 1346386616545796478920950773328;
                                                                                        y = ((y * x) >> 96) + 57155421227552351082224309758442;
                                                                                        int256 p = y + x - 94201549194550492254356042504812;
                                                                                        p = ((p * y) >> 96) + 28719021644029726153956944680412240;
                                                                                        p = p * x + (4385272521454847904659076985693276 << 96);
                                                                                        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
                                                                                        int256 q = x - 2855989394907223263936484059900;
                                                                                        q = ((q * x) >> 96) + 50020603652535783019961831881945;
                                                                                        q = ((q * x) >> 96) - 533845033583426703283633433725380;
                                                                                        q = ((q * x) >> 96) + 3604857256930695427073651918091429;
                                                                                        q = ((q * x) >> 96) - 14423608567350463180887372962807573;
                                                                                        q = ((q * x) >> 96) + 26449188498355588339934803723976023;
                                                                                        assembly {
                                                                                            // Div in assembly because solidity adds a zero check despite the unchecked.
                                                                                            // The q polynomial won't have zeros in the domain as all its roots are complex.
                                                                                            // No scaling is necessary because p is already 2**96 too large.
                                                                                            r := sdiv(p, q)
                                                                                        }
                                                                                        // r should be in the range (0.09, 0.25) * 2**96.
                                                                                        // We now need to multiply r by:
                                                                                        // * the scale factor s = ~6.031367120.
                                                                                        // * the 2**k factor from the range reduction.
                                                                                        // * the 1e18 / 2**96 factor for base conversion.
                                                                                        // We do this all at once, with an intermediate result in 2**213
                                                                                        // basis, so the final right shift is always by a positive amount.
                                                                                        r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
                                                                                    }
                                                                                }
                                                                                function lnWad(int256 x) internal pure returns (int256 r) {
                                                                                    unchecked {
                                                                                        require(x > 0, "UNDEFINED");
                                                                                        // We want to convert x from 10**18 fixed point to 2**96 fixed point.
                                                                                        // We do this by multiplying by 2**96 / 10**18. But since
                                                                                        // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
                                                                                        // and add ln(2**96 / 10**18) at the end.
                                                                                        // Reduce range of x to (1, 2) * 2**96
                                                                                        // ln(2^k * x) = k * ln(2) + ln(x)
                                                                                        int256 k = int256(log2(uint256(x))) - 96;
                                                                                        x <<= uint256(159 - k);
                                                                                        x = int256(uint256(x) >> 159);
                                                                                        // Evaluate using a (8, 8)-term rational approximation.
                                                                                        // p is made monic, we will multiply by a scale factor later.
                                                                                        int256 p = x + 3273285459638523848632254066296;
                                                                                        p = ((p * x) >> 96) + 24828157081833163892658089445524;
                                                                                        p = ((p * x) >> 96) + 43456485725739037958740375743393;
                                                                                        p = ((p * x) >> 96) - 11111509109440967052023855526967;
                                                                                        p = ((p * x) >> 96) - 45023709667254063763336534515857;
                                                                                        p = ((p * x) >> 96) - 14706773417378608786704636184526;
                                                                                        p = p * x - (795164235651350426258249787498 << 96);
                                                                                        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
                                                                                        // q is monic by convention.
                                                                                        int256 q = x + 5573035233440673466300451813936;
                                                                                        q = ((q * x) >> 96) + 71694874799317883764090561454958;
                                                                                        q = ((q * x) >> 96) + 283447036172924575727196451306956;
                                                                                        q = ((q * x) >> 96) + 401686690394027663651624208769553;
                                                                                        q = ((q * x) >> 96) + 204048457590392012362485061816622;
                                                                                        q = ((q * x) >> 96) + 31853899698501571402653359427138;
                                                                                        q = ((q * x) >> 96) + 909429971244387300277376558375;
                                                                                        assembly {
                                                                                            // Div in assembly because solidity adds a zero check despite the unchecked.
                                                                                            // The q polynomial is known not to have zeros in the domain.
                                                                                            // No scaling required because p is already 2**96 too large.
                                                                                            r := sdiv(p, q)
                                                                                        }
                                                                                        // r is in the range (0, 0.125) * 2**96
                                                                                        // Finalization, we need to:
                                                                                        // * multiply by the scale factor s = 5.549…
                                                                                        // * add ln(2**96 / 10**18)
                                                                                        // * add k * ln(2)
                                                                                        // * multiply by 10**18 / 2**96 = 5**18 >> 78
                                                                                        // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
                                                                                        r *= 1677202110996718588342820967067443963516166;
                                                                                        // add ln(2) * k * 5e18 * 2**192
                                                                                        r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
                                                                                        // add ln(2**96 / 10**18) * 5e18 * 2**192
                                                                                        r += 600920179829731861736702779321621459595472258049074101567377883020018308;
                                                                                        // base conversion: mul 2**18 / 2**192
                                                                                        r >>= 174;
                                                                                    }
                                                                                }
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                LOW LEVEL FIXED POINT OPERATIONS
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                function mulDivDown(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        // Store x * y in z for now.
                                                                                        z := mul(x, y)
                                                                                        // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
                                                                                        if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                                                                                            revert(0, 0)
                                                                                        }
                                                                                        // Divide z by the denominator.
                                                                                        z := div(z, denominator)
                                                                                    }
                                                                                }
                                                                                function mulDivUp(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        // Store x * y in z for now.
                                                                                        z := mul(x, y)
                                                                                        // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
                                                                                        if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                                                                                            revert(0, 0)
                                                                                        }
                                                                                        // First, divide z - 1 by the denominator and add 1.
                                                                                        // We allow z - 1 to underflow if z is 0, because we multiply the
                                                                                        // end result by 0 if z is zero, ensuring we return 0 if z is zero.
                                                                                        z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
                                                                                    }
                                                                                }
                                                                                function rpow(
                                                                                    uint256 x,
                                                                                    uint256 n,
                                                                                    uint256 scalar
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        switch x
                                                                                        case 0 {
                                                                                            switch n
                                                                                            case 0 {
                                                                                                // 0 ** 0 = 1
                                                                                                z := scalar
                                                                                            }
                                                                                            default {
                                                                                                // 0 ** n = 0
                                                                                                z := 0
                                                                                            }
                                                                                        }
                                                                                        default {
                                                                                            switch mod(n, 2)
                                                                                            case 0 {
                                                                                                // If n is even, store scalar in z for now.
                                                                                                z := scalar
                                                                                            }
                                                                                            default {
                                                                                                // If n is odd, store x in z for now.
                                                                                                z := x
                                                                                            }
                                                                                            // Shifting right by 1 is like dividing by 2.
                                                                                            let half := shr(1, scalar)
                                                                                            for {
                                                                                                // Shift n right by 1 before looping to halve it.
                                                                                                n := shr(1, n)
                                                                                            } n {
                                                                                                // Shift n right by 1 each iteration to halve it.
                                                                                                n := shr(1, n)
                                                                                            } {
                                                                                                // Revert immediately if x ** 2 would overflow.
                                                                                                // Equivalent to iszero(eq(div(xx, x), x)) here.
                                                                                                if shr(128, x) {
                                                                                                    revert(0, 0)
                                                                                                }
                                                                                                // Store x squared.
                                                                                                let xx := mul(x, x)
                                                                                                // Round to the nearest number.
                                                                                                let xxRound := add(xx, half)
                                                                                                // Revert if xx + half overflowed.
                                                                                                if lt(xxRound, xx) {
                                                                                                    revert(0, 0)
                                                                                                }
                                                                                                // Set x to scaled xxRound.
                                                                                                x := div(xxRound, scalar)
                                                                                                // If n is even:
                                                                                                if mod(n, 2) {
                                                                                                    // Compute z * x.
                                                                                                    let zx := mul(z, x)
                                                                                                    // If z * x overflowed:
                                                                                                    if iszero(eq(div(zx, x), z)) {
                                                                                                        // Revert if x is non-zero.
                                                                                                        if iszero(iszero(x)) {
                                                                                                            revert(0, 0)
                                                                                                        }
                                                                                                    }
                                                                                                    // Round to the nearest number.
                                                                                                    let zxRound := add(zx, half)
                                                                                                    // Revert if zx + half overflowed.
                                                                                                    if lt(zxRound, zx) {
                                                                                                        revert(0, 0)
                                                                                                    }
                                                                                                    // Return properly scaled zxRound.
                                                                                                    z := div(zxRound, scalar)
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                    GENERAL NUMBER UTILITIES
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                function sqrt(uint256 x) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        let y := x // We start y at x, which will help us make our initial estimate.
                                                                                        z := 181 // The "correct" value is 1, but this saves a multiplication later.
                                                                                        // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
                                                                                        // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
                                                                                        // We check y >= 2^(k + 8) but shift right by k bits
                                                                                        // each branch to ensure that if x >= 256, then y >= 256.
                                                                                        if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                                                                                            y := shr(128, y)
                                                                                            z := shl(64, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x1000000000000000000)) {
                                                                                            y := shr(64, y)
                                                                                            z := shl(32, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x10000000000)) {
                                                                                            y := shr(32, y)
                                                                                            z := shl(16, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x1000000)) {
                                                                                            y := shr(16, y)
                                                                                            z := shl(8, z)
                                                                                        }
                                                                                        // Goal was to get z*z*y within a small factor of x. More iterations could
                                                                                        // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
                                                                                        // We ensured y >= 256 so that the relative difference between y and y+1 is small.
                                                                                        // That's not possible if x < 256 but we can just verify those cases exhaustively.
                                                                                        // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
                                                                                        // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
                                                                                        // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
                                                                                        // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
                                                                                        // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
                                                                                        // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
                                                                                        // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
                                                                                        // There is no overflow risk here since y < 2^136 after the first branch above.
                                                                                        z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
                                                                                        // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        // If x+1 is a perfect square, the Babylonian method cycles between
                                                                                        // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
                                                                                        // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
                                                                                        // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
                                                                                        // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
                                                                                        z := sub(z, lt(div(x, z), z))
                                                                                    }
                                                                                }
                                                                                function log2(uint256 x) internal pure returns (uint256 r) {
                                                                                    require(x > 0, "UNDEFINED");
                                                                                    assembly {
                                                                                        r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
                                                                                        r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
                                                                                        r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
                                                                                        r := or(r, shl(4, lt(0xffff, shr(r, x))))
                                                                                        r := or(r, shl(3, lt(0xff, shr(r, x))))
                                                                                        r := or(r, shl(2, lt(0xf, shr(r, x))))
                                                                                        r := or(r, shl(1, lt(0x3, shr(r, x))))
                                                                                        r := or(r, lt(0x1, shr(r, x)))
                                                                                    }
                                                                                }
                                                                            }
                                                                            

                                                                            File 3 of 10: L1ChugSplashProxy
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >0.5.0 <0.8.0;
                                                                            import { iL1ChugSplashDeployer } from "./interfaces/iL1ChugSplashDeployer.sol";
                                                                            /**
                                                                             * @title L1ChugSplashProxy
                                                                             * @dev 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. Nifty!
                                                                             *
                                                                             * 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 {
                                                                                /*************
                                                                                 * Constants *
                                                                                 *************/
                                                                                // "Magic" prefix. When prepended to some arbitrary bytecode and used to create a contract, the
                                                                                // appended bytecode will be deployed as given.
                                                                                bytes13 constant internal DEPLOY_CODE_PREFIX = 0x600D380380600D6000396000f3;
                                                                                // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
                                                                                bytes32 constant internal IMPLEMENTATION_KEY = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                                                                                // bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
                                                                                bytes32 constant internal OWNER_KEY = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                                                                                /***************
                                                                                 * Constructor *
                                                                                 ***************/
                                                                                
                                                                                /**
                                                                                 * @param _owner Address of the initial contract owner.
                                                                                 */
                                                                                constructor(
                                                                                    address _owner
                                                                                ) {
                                                                                    _setOwner(_owner);
                                                                                }
                                                                                /**********************
                                                                                 * Function Modifiers *
                                                                                 **********************/
                                                                                /**
                                                                                 * 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"
                                                                                        );
                                                                                    }
                                                                                    _;
                                                                                }
                                                                                /**
                                                                                 * 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.
                                                                                 */
                                                                                modifier proxyCallIfNotOwner() {
                                                                                    if (msg.sender == _getOwner() || msg.sender == address(0)) {
                                                                                        _;
                                                                                    } else {
                                                                                        // This WILL halt the call frame on completion.
                                                                                        _doProxyCall();
                                                                                    }
                                                                                }
                                                                                /*********************
                                                                                 * Fallback Function *
                                                                                 *********************/
                                                                                fallback()
                                                                                    external
                                                                                    payable
                                                                                {
                                                                                    // Proxy call by default.
                                                                                    _doProxyCall();
                                                                                }
                                                                                /********************
                                                                                 * Public Functions *
                                                                                 ********************/
                                                                                /**
                                                                                 * Sets the code that should be running behind this proxy. Note that 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
                                                                                )
                                                                                    proxyCallIfNotOwner
                                                                                    public
                                                                                {
                                                                                    // 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);
                                                                                }
                                                                                /**
                                                                                 * 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
                                                                                )
                                                                                    proxyCallIfNotOwner
                                                                                    public
                                                                                {
                                                                                    assembly {
                                                                                        sstore(_key, _value)
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * Changes the owner of the proxy contract. Only callable by the owner.
                                                                                 * @param _owner New owner of the proxy contract.
                                                                                 */
                                                                                function setOwner(
                                                                                    address _owner
                                                                                )
                                                                                    proxyCallIfNotOwner
                                                                                    public
                                                                                {
                                                                                    _setOwner(_owner);
                                                                                }
                                                                                /**
                                                                                 * 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()
                                                                                    proxyCallIfNotOwner
                                                                                    public
                                                                                    returns (
                                                                                        address
                                                                                    )
                                                                                {
                                                                                    return _getOwner();
                                                                                }
                                                                                /**
                                                                                 * 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()
                                                                                    proxyCallIfNotOwner
                                                                                    public
                                                                                    returns (
                                                                                        address
                                                                                    )
                                                                                {
                                                                                    return _getImplementation();
                                                                                }
                                                                                /**********************
                                                                                 * Internal Functions *
                                                                                 **********************/
                                                                                /**
                                                                                 * Sets the implementation address.
                                                                                 * @param _implementation New implementation address.
                                                                                 */
                                                                                function _setImplementation(
                                                                                    address _implementation
                                                                                )
                                                                                    internal
                                                                                {
                                                                                    assembly {
                                                                                        sstore(IMPLEMENTATION_KEY, _implementation)
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * Queries the implementation address.
                                                                                 * @return Implementation address.
                                                                                 */
                                                                                function _getImplementation()
                                                                                    internal
                                                                                    view
                                                                                    returns (
                                                                                        address
                                                                                    )
                                                                                {
                                                                                    address implementation;
                                                                                    assembly {
                                                                                        implementation := sload(IMPLEMENTATION_KEY)
                                                                                    }
                                                                                    return implementation;
                                                                                }
                                                                                /**
                                                                                 * 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)
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * 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;
                                                                                }
                                                                                /**
                                                                                 * 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;
                                                                                }
                                                                                /**
                                                                                 * Performs the proxy call via a delegatecall.
                                                                                 */
                                                                                function _doProxyCall()
                                                                                    onlyWhenNotPaused
                                                                                    internal
                                                                                {
                                                                                    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())
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >0.5.0 <0.8.0;
                                                                            /**
                                                                             * @title iL1ChugSplashDeployer
                                                                             */
                                                                            interface iL1ChugSplashDeployer {
                                                                                function isUpgrading()
                                                                                    external
                                                                                    view
                                                                                    returns (
                                                                                        bool
                                                                                    );
                                                                            }
                                                                            

                                                                            File 4 of 10: Lib_ResolvedDelegateProxy
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >=0.6.0 <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 () internal {
                                                                                    address msgSender = _msgSender();
                                                                                    _owner = msgSender;
                                                                                    emit OwnershipTransferred(address(0), msgSender);
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the address of the current owner.
                                                                                 */
                                                                                function owner() public view virtual returns (address) {
                                                                                    return _owner;
                                                                                }
                                                                                /**
                                                                                 * @dev Throws if called by any account other than the owner.
                                                                                 */
                                                                                modifier onlyOwner() {
                                                                                    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 {
                                                                                    emit OwnershipTransferred(_owner, address(0));
                                                                                    _owner = 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");
                                                                                    emit OwnershipTransferred(_owner, newOwner);
                                                                                    _owner = newOwner;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >=0.6.0 <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 GSN 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 payable) {
                                                                                    return msg.sender;
                                                                                }
                                                                                function _msgData() internal view virtual returns (bytes memory) {
                                                                                    this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                                                                                    return msg.data;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >0.5.0 <0.8.0;
                                                                            /* External Imports */
                                                                            import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
                                                                            /**
                                                                             * @title Lib_AddressManager
                                                                             */
                                                                            contract Lib_AddressManager is Ownable {
                                                                                /**********
                                                                                 * Events *
                                                                                 **********/
                                                                                event AddressSet(
                                                                                    string indexed _name,
                                                                                    address _newAddress,
                                                                                    address _oldAddress
                                                                                );
                                                                                /*************
                                                                                 * Variables *
                                                                                 *************/
                                                                                mapping (bytes32 => address) private addresses;
                                                                                /********************
                                                                                 * Public Functions *
                                                                                 ********************/
                                                                                /**
                                                                                 * 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
                                                                                    );
                                                                                }
                                                                                /**
                                                                                 * 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)];
                                                                                }
                                                                                /**********************
                                                                                 * Internal Functions *
                                                                                 **********************/
                                                                                /**
                                                                                 * 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.5.0 <0.8.0;
                                                                            /* Library Imports */
                                                                            import { Lib_AddressManager } from "./Lib_AddressManager.sol";
                                                                            /**
                                                                             * @title Lib_ResolvedDelegateProxy
                                                                             */
                                                                            contract Lib_ResolvedDelegateProxy {
                                                                                /*************
                                                                                 * Variables *
                                                                                 *************/
                                                                                // Using mappings to store fields to avoid overwriting storage slots in the
                                                                                // implementation contract. For example, instead of storing these fields at
                                                                                // storage slot `0` & `1`, they are stored at `keccak256(key + slot)`.
                                                                                // See: https://solidity.readthedocs.io/en/v0.7.0/internals/layout_in_storage.html
                                                                                // NOTE: Do not use this code in your own contract system.
                                                                                //      There is a known flaw in this contract, and we will remove it from the repository
                                                                                //      in the near future. Due to the very limited way that we are using it, this flaw is
                                                                                //      not an issue in our system.
                                                                                mapping (address => string) private implementationName;
                                                                                mapping (address => Lib_AddressManager) private addressManager;
                                                                                /***************
                                                                                 * Constructor *
                                                                                 ***************/
                                                                                /**
                                                                                 * @param _libAddressManager Address of the Lib_AddressManager.
                                                                                 * @param _implementationName implementationName of the contract to proxy to.
                                                                                 */
                                                                                constructor(
                                                                                    address _libAddressManager,
                                                                                    string memory _implementationName
                                                                                ) {
                                                                                    addressManager[address(this)] = Lib_AddressManager(_libAddressManager);
                                                                                    implementationName[address(this)] = _implementationName;
                                                                                }
                                                                                /*********************
                                                                                 * Fallback Function *
                                                                                 *********************/
                                                                                fallback()
                                                                                    external
                                                                                    payable
                                                                                {
                                                                                    address target = addressManager[address(this)].getAddress(
                                                                                        (implementationName[address(this)])
                                                                                    );
                                                                                    require(
                                                                                        target != address(0),
                                                                                        "Target address must be initialized."
                                                                                    );
                                                                                    (bool success, bytes memory returndata) = target.delegatecall(msg.data);
                                                                                    if (success == true) {
                                                                                        assembly {
                                                                                            return(add(returndata, 0x20), mload(returndata))
                                                                                        }
                                                                                    } else {
                                                                                        assembly {
                                                                                            revert(add(returndata, 0x20), mload(returndata))
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                            

                                                                            File 5 of 10: Proxy
                                                                            // 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;
                                                                                }
                                                                            }
                                                                            

                                                                            File 6 of 10: Proxy
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { Constants } from "../libraries/Constants.sol";
                                                                            /// @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 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 {
                                                                                    bytes32 proxyImplementation = Constants.PROXY_IMPLEMENTATION_ADDRESS;
                                                                                    assembly {
                                                                                        sstore(proxyImplementation, _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();
                                                                                    bytes32 proxyOwner = Constants.PROXY_OWNER_ADDRESS;
                                                                                    assembly {
                                                                                        sstore(proxyOwner, _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;
                                                                                    bytes32 proxyImplementation = Constants.PROXY_IMPLEMENTATION_ADDRESS;
                                                                                    assembly {
                                                                                        impl := sload(proxyImplementation)
                                                                                    }
                                                                                    return impl;
                                                                                }
                                                                                /// @notice Queries the owner of the proxy contract.
                                                                                /// @return Owner address.
                                                                                function _getAdmin() internal view returns (address) {
                                                                                    address owner;
                                                                                    bytes32 proxyOwner = Constants.PROXY_OWNER_ADDRESS;
                                                                                    assembly {
                                                                                        owner := sload(proxyOwner)
                                                                                    }
                                                                                    return owner;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity ^0.8.0;
                                                                            import { ResourceMetering } from "../L1/ResourceMetering.sol";
                                                                            /// @title Constants
                                                                            /// @notice Constants is a library for storing constants. Simple! Don't put everything in here, just
                                                                            ///         the stuff used in multiple contracts. Constants that only apply to a single contract
                                                                            ///         should be defined in that contract instead.
                                                                            library Constants {
                                                                                /// @notice Special address to be used as the tx origin for gas estimation calls in the
                                                                                ///         OptimismPortal and CrossDomainMessenger calls. You only need to use this address if
                                                                                ///         the minimum gas limit specified by the user is not actually enough to execute the
                                                                                ///         given message and you're attempting to estimate the actual necessary gas limit. We
                                                                                ///         use address(1) because it's the ecrecover precompile and therefore guaranteed to
                                                                                ///         never have any code on any EVM chain.
                                                                                address internal constant ESTIMATION_ADDRESS = address(1);
                                                                                /// @notice Value used for the L2 sender storage slot in both the OptimismPortal and the
                                                                                ///         CrossDomainMessenger contracts before an actual sender is set. This value is
                                                                                ///         non-zero to reduce the gas cost of message passing transactions.
                                                                                address internal constant DEFAULT_L2_SENDER = 0x000000000000000000000000000000000000dEaD;
                                                                                /// @notice The storage slot that holds the address of a proxy implementation.
                                                                                /// @dev `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)`
                                                                                bytes32 internal constant PROXY_IMPLEMENTATION_ADDRESS =
                                                                                    0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                                                                                /// @notice The storage slot that holds the address of the owner.
                                                                                /// @dev `bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)`
                                                                                bytes32 internal constant PROXY_OWNER_ADDRESS = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                                                                                /// @notice Returns the default values for the ResourceConfig. These are the recommended values
                                                                                ///         for a production network.
                                                                                function DEFAULT_RESOURCE_CONFIG() internal pure returns (ResourceMetering.ResourceConfig memory) {
                                                                                    ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({
                                                                                        maxResourceLimit: 20_000_000,
                                                                                        elasticityMultiplier: 10,
                                                                                        baseFeeMaxChangeDenominator: 8,
                                                                                        minimumBaseFee: 1 gwei,
                                                                                        systemTxMaxGas: 1_000_000,
                                                                                        maximumBaseFee: type(uint128).max
                                                                                    });
                                                                                    return config;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
                                                                            import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
                                                                            import { Burn } from "../libraries/Burn.sol";
                                                                            import { Arithmetic } from "../libraries/Arithmetic.sol";
                                                                            /// @custom:upgradeable
                                                                            /// @title ResourceMetering
                                                                            /// @notice ResourceMetering implements an EIP-1559 style resource metering system where pricing
                                                                            ///         updates automatically based on current demand.
                                                                            abstract contract ResourceMetering is Initializable {
                                                                                /// @notice Represents the various parameters that control the way in which resources are
                                                                                ///         metered. Corresponds to the EIP-1559 resource metering system.
                                                                                /// @custom:field prevBaseFee   Base fee from the previous block(s).
                                                                                /// @custom:field prevBoughtGas Amount of gas bought so far in the current block.
                                                                                /// @custom:field prevBlockNum  Last block number that the base fee was updated.
                                                                                struct ResourceParams {
                                                                                    uint128 prevBaseFee;
                                                                                    uint64 prevBoughtGas;
                                                                                    uint64 prevBlockNum;
                                                                                }
                                                                                /// @notice Represents the configuration for the EIP-1559 based curve for the deposit gas
                                                                                ///         market. These values should be set with care as it is possible to set them in
                                                                                ///         a way that breaks the deposit gas market. The target resource limit is defined as
                                                                                ///         maxResourceLimit / elasticityMultiplier. This struct was designed to fit within a
                                                                                ///         single word. There is additional space for additions in the future.
                                                                                /// @custom:field maxResourceLimit             Represents the maximum amount of deposit gas that
                                                                                ///                                            can be purchased per block.
                                                                                /// @custom:field elasticityMultiplier         Determines the target resource limit along with
                                                                                ///                                            the resource limit.
                                                                                /// @custom:field baseFeeMaxChangeDenominator  Determines max change on fee per block.
                                                                                /// @custom:field minimumBaseFee               The min deposit base fee, it is clamped to this
                                                                                ///                                            value.
                                                                                /// @custom:field systemTxMaxGas               The amount of gas supplied to the system
                                                                                ///                                            transaction. This should be set to the same
                                                                                ///                                            number that the op-node sets as the gas limit
                                                                                ///                                            for the system transaction.
                                                                                /// @custom:field maximumBaseFee               The max deposit base fee, it is clamped to this
                                                                                ///                                            value.
                                                                                struct ResourceConfig {
                                                                                    uint32 maxResourceLimit;
                                                                                    uint8 elasticityMultiplier;
                                                                                    uint8 baseFeeMaxChangeDenominator;
                                                                                    uint32 minimumBaseFee;
                                                                                    uint32 systemTxMaxGas;
                                                                                    uint128 maximumBaseFee;
                                                                                }
                                                                                /// @notice EIP-1559 style gas parameters.
                                                                                ResourceParams public params;
                                                                                /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades.
                                                                                uint256[48] private __gap;
                                                                                /// @notice Meters access to a function based an amount of a requested resource.
                                                                                /// @param _amount Amount of the resource requested.
                                                                                modifier metered(uint64 _amount) {
                                                                                    // Record initial gas amount so we can refund for it later.
                                                                                    uint256 initialGas = gasleft();
                                                                                    // Run the underlying function.
                                                                                    _;
                                                                                    // Run the metering function.
                                                                                    _metered(_amount, initialGas);
                                                                                }
                                                                                /// @notice An internal function that holds all of the logic for metering a resource.
                                                                                /// @param _amount     Amount of the resource requested.
                                                                                /// @param _initialGas The amount of gas before any modifier execution.
                                                                                function _metered(uint64 _amount, uint256 _initialGas) internal {
                                                                                    // Update block number and base fee if necessary.
                                                                                    uint256 blockDiff = block.number - params.prevBlockNum;
                                                                                    ResourceConfig memory config = _resourceConfig();
                                                                                    int256 targetResourceLimit =
                                                                                        int256(uint256(config.maxResourceLimit)) / int256(uint256(config.elasticityMultiplier));
                                                                                    if (blockDiff > 0) {
                                                                                        // Handle updating EIP-1559 style gas parameters. We use EIP-1559 to restrict the rate
                                                                                        // at which deposits can be created and therefore limit the potential for deposits to
                                                                                        // spam the L2 system. Fee scheme is very similar to EIP-1559 with minor changes.
                                                                                        int256 gasUsedDelta = int256(uint256(params.prevBoughtGas)) - targetResourceLimit;
                                                                                        int256 baseFeeDelta = (int256(uint256(params.prevBaseFee)) * gasUsedDelta)
                                                                                            / (targetResourceLimit * int256(uint256(config.baseFeeMaxChangeDenominator)));
                                                                                        // Update base fee by adding the base fee delta and clamp the resulting value between
                                                                                        // min and max.
                                                                                        int256 newBaseFee = Arithmetic.clamp({
                                                                                            _value: int256(uint256(params.prevBaseFee)) + baseFeeDelta,
                                                                                            _min: int256(uint256(config.minimumBaseFee)),
                                                                                            _max: int256(uint256(config.maximumBaseFee))
                                                                                        });
                                                                                        // If we skipped more than one block, we also need to account for every empty block.
                                                                                        // Empty block means there was no demand for deposits in that block, so we should
                                                                                        // reflect this lack of demand in the fee.
                                                                                        if (blockDiff > 1) {
                                                                                            // Update the base fee by repeatedly applying the exponent 1-(1/change_denominator)
                                                                                            // blockDiff - 1 times. Simulates multiple empty blocks. Clamp the resulting value
                                                                                            // between min and max.
                                                                                            newBaseFee = Arithmetic.clamp({
                                                                                                _value: Arithmetic.cdexp({
                                                                                                    _coefficient: newBaseFee,
                                                                                                    _denominator: int256(uint256(config.baseFeeMaxChangeDenominator)),
                                                                                                    _exponent: int256(blockDiff - 1)
                                                                                                }),
                                                                                                _min: int256(uint256(config.minimumBaseFee)),
                                                                                                _max: int256(uint256(config.maximumBaseFee))
                                                                                            });
                                                                                        }
                                                                                        // Update new base fee, reset bought gas, and update block number.
                                                                                        params.prevBaseFee = uint128(uint256(newBaseFee));
                                                                                        params.prevBoughtGas = 0;
                                                                                        params.prevBlockNum = uint64(block.number);
                                                                                    }
                                                                                    // Make sure we can actually buy the resource amount requested by the user.
                                                                                    params.prevBoughtGas += _amount;
                                                                                    require(
                                                                                        int256(uint256(params.prevBoughtGas)) <= int256(uint256(config.maxResourceLimit)),
                                                                                        "ResourceMetering: cannot buy more gas than available gas limit"
                                                                                    );
                                                                                    // Determine the amount of ETH to be paid.
                                                                                    uint256 resourceCost = uint256(_amount) * uint256(params.prevBaseFee);
                                                                                    // We currently charge for this ETH amount as an L1 gas burn, so we convert the ETH amount
                                                                                    // into gas by dividing by the L1 base fee. We assume a minimum base fee of 1 gwei to avoid
                                                                                    // division by zero for L1s that don't support 1559 or to avoid excessive gas burns during
                                                                                    // periods of extremely low L1 demand. One-day average gas fee hasn't dipped below 1 gwei
                                                                                    // during any 1 day period in the last 5 years, so should be fine.
                                                                                    uint256 gasCost = resourceCost / Math.max(block.basefee, 1 gwei);
                                                                                    // Give the user a refund based on the amount of gas they used to do all of the work up to
                                                                                    // this point. Since we're at the end of the modifier, this should be pretty accurate. Acts
                                                                                    // effectively like a dynamic stipend (with a minimum value).
                                                                                    uint256 usedGas = _initialGas - gasleft();
                                                                                    if (gasCost > usedGas) {
                                                                                        Burn.gas(gasCost - usedGas);
                                                                                    }
                                                                                }
                                                                                /// @notice Virtual function that returns the resource config.
                                                                                ///         Contracts that inherit this contract must implement this function.
                                                                                /// @return ResourceConfig
                                                                                function _resourceConfig() internal virtual returns (ResourceConfig memory);
                                                                                /// @notice Sets initial resource parameter values.
                                                                                ///         This function must either be called by the initializer function of an upgradeable
                                                                                ///         child contract.
                                                                                // solhint-disable-next-line func-name-mixedcase
                                                                                function __ResourceMetering_init() internal onlyInitializing {
                                                                                    params = ResourceParams({ prevBaseFee: 1 gwei, prevBoughtGas: 0, prevBlockNum: uint64(block.number) });
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
                                                                            pragma solidity ^0.8.2;
                                                                            import "../../utils/Address.sol";
                                                                            /**
                                                                             * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                                                                             * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
                                                                             * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                                                                             * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                                                                             *
                                                                             * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
                                                                             * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
                                                                             * case an upgrade adds a module that needs to be initialized.
                                                                             *
                                                                             * For example:
                                                                             *
                                                                             * [.hljs-theme-light.nopadding]
                                                                             * ```
                                                                             * contract MyToken is ERC20Upgradeable {
                                                                             *     function initialize() initializer public {
                                                                             *         __ERC20_init("MyToken", "MTK");
                                                                             *     }
                                                                             * }
                                                                             * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
                                                                             *     function initializeV2() reinitializer(2) public {
                                                                             *         __ERC20Permit_init("MyToken");
                                                                             *     }
                                                                             * }
                                                                             * ```
                                                                             *
                                                                             * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                                                                             * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                                                                             *
                                                                             * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                                                                             * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                                                                             *
                                                                             * [CAUTION]
                                                                             * ====
                                                                             * Avoid leaving a contract uninitialized.
                                                                             *
                                                                             * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                                                                             * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
                                                                             * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
                                                                             *
                                                                             * [.hljs-theme-light.nopadding]
                                                                             * ```
                                                                             * /// @custom:oz-upgrades-unsafe-allow constructor
                                                                             * constructor() {
                                                                             *     _disableInitializers();
                                                                             * }
                                                                             * ```
                                                                             * ====
                                                                             */
                                                                            abstract contract Initializable {
                                                                                /**
                                                                                 * @dev Indicates that the contract has been initialized.
                                                                                 * @custom:oz-retyped-from bool
                                                                                 */
                                                                                uint8 private _initialized;
                                                                                /**
                                                                                 * @dev Indicates that the contract is in the process of being initialized.
                                                                                 */
                                                                                bool private _initializing;
                                                                                /**
                                                                                 * @dev Triggered when the contract has been initialized or reinitialized.
                                                                                 */
                                                                                event Initialized(uint8 version);
                                                                                /**
                                                                                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                                                                                 * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
                                                                                 */
                                                                                modifier initializer() {
                                                                                    bool isTopLevelCall = !_initializing;
                                                                                    require(
                                                                                        (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
                                                                                        "Initializable: contract is already initialized"
                                                                                    );
                                                                                    _initialized = 1;
                                                                                    if (isTopLevelCall) {
                                                                                        _initializing = true;
                                                                                    }
                                                                                    _;
                                                                                    if (isTopLevelCall) {
                                                                                        _initializing = false;
                                                                                        emit Initialized(1);
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                                                                                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                                                                                 * used to initialize parent contracts.
                                                                                 *
                                                                                 * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
                                                                                 * initialization step. This is essential to configure modules that are added through upgrades and that require
                                                                                 * initialization.
                                                                                 *
                                                                                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                                                                                 * a contract, executing them in the right order is up to the developer or operator.
                                                                                 */
                                                                                modifier reinitializer(uint8 version) {
                                                                                    require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                                                                                    _initialized = version;
                                                                                    _initializing = true;
                                                                                    _;
                                                                                    _initializing = false;
                                                                                    emit Initialized(version);
                                                                                }
                                                                                /**
                                                                                 * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                                                                                 * {initializer} and {reinitializer} modifiers, directly or indirectly.
                                                                                 */
                                                                                modifier onlyInitializing() {
                                                                                    require(_initializing, "Initializable: contract is not initializing");
                                                                                    _;
                                                                                }
                                                                                /**
                                                                                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                                                                                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                                                                                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                                                                                 * through proxies.
                                                                                 */
                                                                                function _disableInitializers() internal virtual {
                                                                                    require(!_initializing, "Initializable: contract is initializing");
                                                                                    if (_initialized < type(uint8).max) {
                                                                                        _initialized = type(uint8).max;
                                                                                        emit Initialized(type(uint8).max);
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
                                                                            pragma solidity ^0.8.0;
                                                                            /**
                                                                             * @dev Standard math utilities missing in the Solidity language.
                                                                             */
                                                                            library Math {
                                                                                enum Rounding {
                                                                                    Down, // Toward negative infinity
                                                                                    Up, // Toward infinity
                                                                                    Zero // Toward zero
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the largest of two numbers.
                                                                                 */
                                                                                function max(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    return a >= b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the smallest of two numbers.
                                                                                 */
                                                                                function min(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    return a < b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the average of two numbers. The result is rounded towards
                                                                                 * zero.
                                                                                 */
                                                                                function average(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    // (a + b) / 2 can overflow.
                                                                                    return (a & b) + (a ^ b) / 2;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the ceiling of the division of two numbers.
                                                                                 *
                                                                                 * This differs from standard division with `/` in that it rounds up instead
                                                                                 * of rounding down.
                                                                                 */
                                                                                function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    // (a + b - 1) / b can overflow on addition, so we distribute.
                                                                                    return a == 0 ? 0 : (a - 1) / b + 1;
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
                                                                                 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
                                                                                 * with further edits by Uniswap Labs also under MIT license.
                                                                                 */
                                                                                function mulDiv(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 result) {
                                                                                    unchecked {
                                                                                        // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                                                                                        // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                                                                                        // variables such that product = prod1 * 2^256 + prod0.
                                                                                        uint256 prod0; // Least significant 256 bits of the product
                                                                                        uint256 prod1; // Most significant 256 bits of the product
                                                                                        assembly {
                                                                                            let mm := mulmod(x, y, not(0))
                                                                                            prod0 := mul(x, y)
                                                                                            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                                                                                        }
                                                                                        // Handle non-overflow cases, 256 by 256 division.
                                                                                        if (prod1 == 0) {
                                                                                            return prod0 / denominator;
                                                                                        }
                                                                                        // Make sure the result is less than 2^256. Also prevents denominator == 0.
                                                                                        require(denominator > prod1);
                                                                                        ///////////////////////////////////////////////
                                                                                        // 512 by 256 division.
                                                                                        ///////////////////////////////////////////////
                                                                                        // Make division exact by subtracting the remainder from [prod1 prod0].
                                                                                        uint256 remainder;
                                                                                        assembly {
                                                                                            // Compute remainder using mulmod.
                                                                                            remainder := mulmod(x, y, denominator)
                                                                                            // Subtract 256 bit number from 512 bit number.
                                                                                            prod1 := sub(prod1, gt(remainder, prod0))
                                                                                            prod0 := sub(prod0, remainder)
                                                                                        }
                                                                                        // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                                                                                        // See https://cs.stackexchange.com/q/138556/92363.
                                                                                        // Does not overflow because the denominator cannot be zero at this stage in the function.
                                                                                        uint256 twos = denominator & (~denominator + 1);
                                                                                        assembly {
                                                                                            // Divide denominator by twos.
                                                                                            denominator := div(denominator, twos)
                                                                                            // Divide [prod1 prod0] by twos.
                                                                                            prod0 := div(prod0, twos)
                                                                                            // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                                                                                            twos := add(div(sub(0, twos), twos), 1)
                                                                                        }
                                                                                        // Shift in bits from prod1 into prod0.
                                                                                        prod0 |= prod1 * twos;
                                                                                        // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                                                                                        // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                                                                                        // four bits. That is, denominator * inv = 1 mod 2^4.
                                                                                        uint256 inverse = (3 * denominator) ^ 2;
                                                                                        // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                                                                                        // in modular arithmetic, doubling the correct bits in each step.
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^8
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^16
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^32
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^64
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^128
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^256
                                                                                        // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                                                                                        // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                                                                                        // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                                                                                        // is no longer required.
                                                                                        result = prod0 * inverse;
                                                                                        return result;
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
                                                                                 */
                                                                                function mulDiv(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator,
                                                                                    Rounding rounding
                                                                                ) internal pure returns (uint256) {
                                                                                    uint256 result = mulDiv(x, y, denominator);
                                                                                    if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                                                                                        result += 1;
                                                                                    }
                                                                                    return result;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
                                                                                 *
                                                                                 * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
                                                                                 */
                                                                                function sqrt(uint256 a) internal pure returns (uint256) {
                                                                                    if (a == 0) {
                                                                                        return 0;
                                                                                    }
                                                                                    // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                                                                                    // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                                                                                    // `msb(a) <= a < 2*msb(a)`.
                                                                                    // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
                                                                                    // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
                                                                                    // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
                                                                                    // good first aproximation of `sqrt(a)` with at least 1 correct bit.
                                                                                    uint256 result = 1;
                                                                                    uint256 x = a;
                                                                                    if (x >> 128 > 0) {
                                                                                        x >>= 128;
                                                                                        result <<= 64;
                                                                                    }
                                                                                    if (x >> 64 > 0) {
                                                                                        x >>= 64;
                                                                                        result <<= 32;
                                                                                    }
                                                                                    if (x >> 32 > 0) {
                                                                                        x >>= 32;
                                                                                        result <<= 16;
                                                                                    }
                                                                                    if (x >> 16 > 0) {
                                                                                        x >>= 16;
                                                                                        result <<= 8;
                                                                                    }
                                                                                    if (x >> 8 > 0) {
                                                                                        x >>= 8;
                                                                                        result <<= 4;
                                                                                    }
                                                                                    if (x >> 4 > 0) {
                                                                                        x >>= 4;
                                                                                        result <<= 2;
                                                                                    }
                                                                                    if (x >> 2 > 0) {
                                                                                        result <<= 1;
                                                                                    }
                                                                                    // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                                                                                    // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                                                                                    // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                                                                                    // into the expected uint128 result.
                                                                                    unchecked {
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        return min(result, a / result);
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates sqrt(a), following the selected rounding direction.
                                                                                 */
                                                                                function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                                                                                    uint256 result = sqrt(a);
                                                                                    if (rounding == Rounding.Up && result * result < a) {
                                                                                        result += 1;
                                                                                    }
                                                                                    return result;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            /// @title Burn
                                                                            /// @notice Utilities for burning stuff.
                                                                            library Burn {
                                                                                /// @notice Burns a given amount of ETH.
                                                                                /// @param _amount Amount of ETH to burn.
                                                                                function eth(uint256 _amount) internal {
                                                                                    new Burner{ value: _amount }();
                                                                                }
                                                                                /// @notice Burns a given amount of gas.
                                                                                /// @param _amount Amount of gas to burn.
                                                                                function gas(uint256 _amount) internal view {
                                                                                    uint256 i = 0;
                                                                                    uint256 initialGas = gasleft();
                                                                                    while (initialGas - gasleft() < _amount) {
                                                                                        ++i;
                                                                                    }
                                                                                }
                                                                            }
                                                                            /// @title Burner
                                                                            /// @notice Burner self-destructs on creation and sends all ETH to itself, removing all ETH given to
                                                                            ///         the contract from the circulating supply. Self-destructing is the only way to remove ETH
                                                                            ///         from the circulating supply.
                                                                            contract Burner {
                                                                                constructor() payable {
                                                                                    selfdestruct(payable(address(this)));
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { SignedMath } from "@openzeppelin/contracts/utils/math/SignedMath.sol";
                                                                            import { FixedPointMathLib } from "@rari-capital/solmate/src/utils/FixedPointMathLib.sol";
                                                                            /// @title Arithmetic
                                                                            /// @notice Even more math than before.
                                                                            library Arithmetic {
                                                                                /// @notice Clamps a value between a minimum and maximum.
                                                                                /// @param _value The value to clamp.
                                                                                /// @param _min   The minimum value.
                                                                                /// @param _max   The maximum value.
                                                                                /// @return The clamped value.
                                                                                function clamp(int256 _value, int256 _min, int256 _max) internal pure returns (int256) {
                                                                                    return SignedMath.min(SignedMath.max(_value, _min), _max);
                                                                                }
                                                                                /// @notice (c)oefficient (d)enominator (exp)onentiation function.
                                                                                ///         Returns the result of: c * (1 - 1/d)^exp.
                                                                                /// @param _coefficient Coefficient of the function.
                                                                                /// @param _denominator Fractional denominator.
                                                                                /// @param _exponent    Power function exponent.
                                                                                /// @return Result of c * (1 - 1/d)^exp.
                                                                                function cdexp(int256 _coefficient, int256 _denominator, int256 _exponent) internal pure returns (int256) {
                                                                                    return (_coefficient * (FixedPointMathLib.powWad(1e18 - (1e18 / _denominator), _exponent * 1e18))) / 1e18;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
                                                                            pragma solidity ^0.8.1;
                                                                            /**
                                                                             * @dev Collection of functions related to the address type
                                                                             */
                                                                            library Address {
                                                                                /**
                                                                                 * @dev Returns true if `account` is a contract.
                                                                                 *
                                                                                 * [IMPORTANT]
                                                                                 * ====
                                                                                 * It is unsafe to assume that an address for which this function returns
                                                                                 * false is an externally-owned account (EOA) and not a contract.
                                                                                 *
                                                                                 * Among others, `isContract` will return false for the following
                                                                                 * types of addresses:
                                                                                 *
                                                                                 *  - an externally-owned account
                                                                                 *  - a contract in construction
                                                                                 *  - an address where a contract will be created
                                                                                 *  - an address where a contract lived, but was destroyed
                                                                                 * ====
                                                                                 *
                                                                                 * [IMPORTANT]
                                                                                 * ====
                                                                                 * You shouldn't rely on `isContract` to protect against flash loan attacks!
                                                                                 *
                                                                                 * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                                                                                 * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                                                                                 * constructor.
                                                                                 * ====
                                                                                 */
                                                                                function isContract(address account) internal view returns (bool) {
                                                                                    // This method relies on extcodesize/address.code.length, which returns 0
                                                                                    // for contracts in construction, since the code is only stored at the end
                                                                                    // of the constructor execution.
                                                                                    return account.code.length > 0;
                                                                                }
                                                                                /**
                                                                                 * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                                                                                 * `recipient`, forwarding all available gas and reverting on errors.
                                                                                 *
                                                                                 * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                                                                                 * of certain opcodes, possibly making contracts go over the 2300 gas limit
                                                                                 * imposed by `transfer`, making them unable to receive funds via
                                                                                 * `transfer`. {sendValue} removes this limitation.
                                                                                 *
                                                                                 * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                                                                                 *
                                                                                 * IMPORTANT: because control is transferred to `recipient`, care must be
                                                                                 * taken to not create reentrancy vulnerabilities. Consider using
                                                                                 * {ReentrancyGuard} or the
                                                                                 * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                                                                                 */
                                                                                function sendValue(address payable recipient, uint256 amount) internal {
                                                                                    require(address(this).balance >= amount, "Address: insufficient balance");
                                                                                    (bool success, ) = recipient.call{value: amount}("");
                                                                                    require(success, "Address: unable to send value, recipient may have reverted");
                                                                                }
                                                                                /**
                                                                                 * @dev Performs a Solidity function call using a low level `call`. A
                                                                                 * plain `call` is an unsafe replacement for a function call: use this
                                                                                 * function instead.
                                                                                 *
                                                                                 * If `target` reverts with a revert reason, it is bubbled up by this
                                                                                 * function (like regular Solidity function calls).
                                                                                 *
                                                                                 * Returns the raw returned data. To convert to the expected return value,
                                                                                 * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                                                                                 *
                                                                                 * Requirements:
                                                                                 *
                                                                                 * - `target` must be a contract.
                                                                                 * - calling `target` with `data` must not revert.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                                                                    return functionCall(target, data, "Address: low-level call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                                                                                 * `errorMessage` as a fallback revert reason when `target` reverts.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    return functionCallWithValue(target, data, 0, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but also transferring `value` wei to `target`.
                                                                                 *
                                                                                 * Requirements:
                                                                                 *
                                                                                 * - the calling contract must have an ETH balance of at least `value`.
                                                                                 * - the called Solidity function must be `payable`.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCallWithValue(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    uint256 value
                                                                                ) internal returns (bytes memory) {
                                                                                    return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                                                                                 * with `errorMessage` as a fallback revert reason when `target` reverts.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCallWithValue(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    uint256 value,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    require(address(this).balance >= value, "Address: insufficient balance for call");
                                                                                    require(isContract(target), "Address: call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but performing a static call.
                                                                                 *
                                                                                 * _Available since v3.3._
                                                                                 */
                                                                                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                                                                    return functionStaticCall(target, data, "Address: low-level static call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                                                                                 * but performing a static call.
                                                                                 *
                                                                                 * _Available since v3.3._
                                                                                 */
                                                                                function functionStaticCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal view returns (bytes memory) {
                                                                                    require(isContract(target), "Address: static call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.staticcall(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but performing a delegate call.
                                                                                 *
                                                                                 * _Available since v3.4._
                                                                                 */
                                                                                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                                                                    return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                                                                                 * but performing a delegate call.
                                                                                 *
                                                                                 * _Available since v3.4._
                                                                                 */
                                                                                function functionDelegateCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    require(isContract(target), "Address: delegate call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.delegatecall(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                                                                                 * revert reason using the provided one.
                                                                                 *
                                                                                 * _Available since v4.3._
                                                                                 */
                                                                                function verifyCallResult(
                                                                                    bool success,
                                                                                    bytes memory returndata,
                                                                                    string memory errorMessage
                                                                                ) internal pure returns (bytes memory) {
                                                                                    if (success) {
                                                                                        return returndata;
                                                                                    } else {
                                                                                        // Look for revert reason and bubble it up if present
                                                                                        if (returndata.length > 0) {
                                                                                            // The easiest way to bubble the revert reason is using memory via assembly
                                                                                            /// @solidity memory-safe-assembly
                                                                                            assembly {
                                                                                                let returndata_size := mload(returndata)
                                                                                                revert(add(32, returndata), returndata_size)
                                                                                            }
                                                                                        } else {
                                                                                            revert(errorMessage);
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.5.0) (utils/math/SignedMath.sol)
                                                                            pragma solidity ^0.8.0;
                                                                            /**
                                                                             * @dev Standard signed math utilities missing in the Solidity language.
                                                                             */
                                                                            library SignedMath {
                                                                                /**
                                                                                 * @dev Returns the largest of two signed numbers.
                                                                                 */
                                                                                function max(int256 a, int256 b) internal pure returns (int256) {
                                                                                    return a >= b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the smallest of two signed numbers.
                                                                                 */
                                                                                function min(int256 a, int256 b) internal pure returns (int256) {
                                                                                    return a < b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the average of two signed numbers without overflow.
                                                                                 * The result is rounded towards zero.
                                                                                 */
                                                                                function average(int256 a, int256 b) internal pure returns (int256) {
                                                                                    // Formula from the book "Hacker's Delight"
                                                                                    int256 x = (a & b) + ((a ^ b) >> 1);
                                                                                    return x + (int256(uint256(x) >> 255) & (a ^ b));
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the absolute unsigned value of a signed value.
                                                                                 */
                                                                                function abs(int256 n) internal pure returns (uint256) {
                                                                                    unchecked {
                                                                                        // must be unchecked in order to support `n = type(int256).min`
                                                                                        return uint256(n >= 0 ? n : -n);
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >=0.8.0;
                                                                            /// @notice Arithmetic library with operations for fixed-point numbers.
                                                                            /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
                                                                            library FixedPointMathLib {
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                SIMPLIFIED FIXED POINT OPERATIONS
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
                                                                                function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
                                                                                }
                                                                                function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
                                                                                }
                                                                                function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
                                                                                }
                                                                                function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
                                                                                }
                                                                                function powWad(int256 x, int256 y) internal pure returns (int256) {
                                                                                    // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)
                                                                                    return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0.
                                                                                }
                                                                                function expWad(int256 x) internal pure returns (int256 r) {
                                                                                    unchecked {
                                                                                        // When the result is < 0.5 we return zero. This happens when
                                                                                        // x <= floor(log(0.5e18) * 1e18) ~ -42e18
                                                                                        if (x <= -42139678854452767551) return 0;
                                                                                        // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
                                                                                        // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
                                                                                        if (x >= 135305999368893231589) revert("EXP_OVERFLOW");
                                                                                        // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
                                                                                        // for more intermediate precision and a binary basis. This base conversion
                                                                                        // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
                                                                                        x = (x << 78) / 5**18;
                                                                                        // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
                                                                                        // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
                                                                                        // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
                                                                                        int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
                                                                                        x = x - k * 54916777467707473351141471128;
                                                                                        // k is in the range [-61, 195].
                                                                                        // Evaluate using a (6, 7)-term rational approximation.
                                                                                        // p is made monic, we'll multiply by a scale factor later.
                                                                                        int256 y = x + 1346386616545796478920950773328;
                                                                                        y = ((y * x) >> 96) + 57155421227552351082224309758442;
                                                                                        int256 p = y + x - 94201549194550492254356042504812;
                                                                                        p = ((p * y) >> 96) + 28719021644029726153956944680412240;
                                                                                        p = p * x + (4385272521454847904659076985693276 << 96);
                                                                                        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
                                                                                        int256 q = x - 2855989394907223263936484059900;
                                                                                        q = ((q * x) >> 96) + 50020603652535783019961831881945;
                                                                                        q = ((q * x) >> 96) - 533845033583426703283633433725380;
                                                                                        q = ((q * x) >> 96) + 3604857256930695427073651918091429;
                                                                                        q = ((q * x) >> 96) - 14423608567350463180887372962807573;
                                                                                        q = ((q * x) >> 96) + 26449188498355588339934803723976023;
                                                                                        assembly {
                                                                                            // Div in assembly because solidity adds a zero check despite the unchecked.
                                                                                            // The q polynomial won't have zeros in the domain as all its roots are complex.
                                                                                            // No scaling is necessary because p is already 2**96 too large.
                                                                                            r := sdiv(p, q)
                                                                                        }
                                                                                        // r should be in the range (0.09, 0.25) * 2**96.
                                                                                        // We now need to multiply r by:
                                                                                        // * the scale factor s = ~6.031367120.
                                                                                        // * the 2**k factor from the range reduction.
                                                                                        // * the 1e18 / 2**96 factor for base conversion.
                                                                                        // We do this all at once, with an intermediate result in 2**213
                                                                                        // basis, so the final right shift is always by a positive amount.
                                                                                        r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
                                                                                    }
                                                                                }
                                                                                function lnWad(int256 x) internal pure returns (int256 r) {
                                                                                    unchecked {
                                                                                        require(x > 0, "UNDEFINED");
                                                                                        // We want to convert x from 10**18 fixed point to 2**96 fixed point.
                                                                                        // We do this by multiplying by 2**96 / 10**18. But since
                                                                                        // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
                                                                                        // and add ln(2**96 / 10**18) at the end.
                                                                                        // Reduce range of x to (1, 2) * 2**96
                                                                                        // ln(2^k * x) = k * ln(2) + ln(x)
                                                                                        int256 k = int256(log2(uint256(x))) - 96;
                                                                                        x <<= uint256(159 - k);
                                                                                        x = int256(uint256(x) >> 159);
                                                                                        // Evaluate using a (8, 8)-term rational approximation.
                                                                                        // p is made monic, we will multiply by a scale factor later.
                                                                                        int256 p = x + 3273285459638523848632254066296;
                                                                                        p = ((p * x) >> 96) + 24828157081833163892658089445524;
                                                                                        p = ((p * x) >> 96) + 43456485725739037958740375743393;
                                                                                        p = ((p * x) >> 96) - 11111509109440967052023855526967;
                                                                                        p = ((p * x) >> 96) - 45023709667254063763336534515857;
                                                                                        p = ((p * x) >> 96) - 14706773417378608786704636184526;
                                                                                        p = p * x - (795164235651350426258249787498 << 96);
                                                                                        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
                                                                                        // q is monic by convention.
                                                                                        int256 q = x + 5573035233440673466300451813936;
                                                                                        q = ((q * x) >> 96) + 71694874799317883764090561454958;
                                                                                        q = ((q * x) >> 96) + 283447036172924575727196451306956;
                                                                                        q = ((q * x) >> 96) + 401686690394027663651624208769553;
                                                                                        q = ((q * x) >> 96) + 204048457590392012362485061816622;
                                                                                        q = ((q * x) >> 96) + 31853899698501571402653359427138;
                                                                                        q = ((q * x) >> 96) + 909429971244387300277376558375;
                                                                                        assembly {
                                                                                            // Div in assembly because solidity adds a zero check despite the unchecked.
                                                                                            // The q polynomial is known not to have zeros in the domain.
                                                                                            // No scaling required because p is already 2**96 too large.
                                                                                            r := sdiv(p, q)
                                                                                        }
                                                                                        // r is in the range (0, 0.125) * 2**96
                                                                                        // Finalization, we need to:
                                                                                        // * multiply by the scale factor s = 5.549…
                                                                                        // * add ln(2**96 / 10**18)
                                                                                        // * add k * ln(2)
                                                                                        // * multiply by 10**18 / 2**96 = 5**18 >> 78
                                                                                        // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
                                                                                        r *= 1677202110996718588342820967067443963516166;
                                                                                        // add ln(2) * k * 5e18 * 2**192
                                                                                        r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
                                                                                        // add ln(2**96 / 10**18) * 5e18 * 2**192
                                                                                        r += 600920179829731861736702779321621459595472258049074101567377883020018308;
                                                                                        // base conversion: mul 2**18 / 2**192
                                                                                        r >>= 174;
                                                                                    }
                                                                                }
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                LOW LEVEL FIXED POINT OPERATIONS
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                function mulDivDown(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        // Store x * y in z for now.
                                                                                        z := mul(x, y)
                                                                                        // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
                                                                                        if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                                                                                            revert(0, 0)
                                                                                        }
                                                                                        // Divide z by the denominator.
                                                                                        z := div(z, denominator)
                                                                                    }
                                                                                }
                                                                                function mulDivUp(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        // Store x * y in z for now.
                                                                                        z := mul(x, y)
                                                                                        // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
                                                                                        if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                                                                                            revert(0, 0)
                                                                                        }
                                                                                        // First, divide z - 1 by the denominator and add 1.
                                                                                        // We allow z - 1 to underflow if z is 0, because we multiply the
                                                                                        // end result by 0 if z is zero, ensuring we return 0 if z is zero.
                                                                                        z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
                                                                                    }
                                                                                }
                                                                                function rpow(
                                                                                    uint256 x,
                                                                                    uint256 n,
                                                                                    uint256 scalar
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        switch x
                                                                                        case 0 {
                                                                                            switch n
                                                                                            case 0 {
                                                                                                // 0 ** 0 = 1
                                                                                                z := scalar
                                                                                            }
                                                                                            default {
                                                                                                // 0 ** n = 0
                                                                                                z := 0
                                                                                            }
                                                                                        }
                                                                                        default {
                                                                                            switch mod(n, 2)
                                                                                            case 0 {
                                                                                                // If n is even, store scalar in z for now.
                                                                                                z := scalar
                                                                                            }
                                                                                            default {
                                                                                                // If n is odd, store x in z for now.
                                                                                                z := x
                                                                                            }
                                                                                            // Shifting right by 1 is like dividing by 2.
                                                                                            let half := shr(1, scalar)
                                                                                            for {
                                                                                                // Shift n right by 1 before looping to halve it.
                                                                                                n := shr(1, n)
                                                                                            } n {
                                                                                                // Shift n right by 1 each iteration to halve it.
                                                                                                n := shr(1, n)
                                                                                            } {
                                                                                                // Revert immediately if x ** 2 would overflow.
                                                                                                // Equivalent to iszero(eq(div(xx, x), x)) here.
                                                                                                if shr(128, x) {
                                                                                                    revert(0, 0)
                                                                                                }
                                                                                                // Store x squared.
                                                                                                let xx := mul(x, x)
                                                                                                // Round to the nearest number.
                                                                                                let xxRound := add(xx, half)
                                                                                                // Revert if xx + half overflowed.
                                                                                                if lt(xxRound, xx) {
                                                                                                    revert(0, 0)
                                                                                                }
                                                                                                // Set x to scaled xxRound.
                                                                                                x := div(xxRound, scalar)
                                                                                                // If n is even:
                                                                                                if mod(n, 2) {
                                                                                                    // Compute z * x.
                                                                                                    let zx := mul(z, x)
                                                                                                    // If z * x overflowed:
                                                                                                    if iszero(eq(div(zx, x), z)) {
                                                                                                        // Revert if x is non-zero.
                                                                                                        if iszero(iszero(x)) {
                                                                                                            revert(0, 0)
                                                                                                        }
                                                                                                    }
                                                                                                    // Round to the nearest number.
                                                                                                    let zxRound := add(zx, half)
                                                                                                    // Revert if zx + half overflowed.
                                                                                                    if lt(zxRound, zx) {
                                                                                                        revert(0, 0)
                                                                                                    }
                                                                                                    // Return properly scaled zxRound.
                                                                                                    z := div(zxRound, scalar)
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                    GENERAL NUMBER UTILITIES
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                function sqrt(uint256 x) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        let y := x // We start y at x, which will help us make our initial estimate.
                                                                                        z := 181 // The "correct" value is 1, but this saves a multiplication later.
                                                                                        // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
                                                                                        // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
                                                                                        // We check y >= 2^(k + 8) but shift right by k bits
                                                                                        // each branch to ensure that if x >= 256, then y >= 256.
                                                                                        if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                                                                                            y := shr(128, y)
                                                                                            z := shl(64, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x1000000000000000000)) {
                                                                                            y := shr(64, y)
                                                                                            z := shl(32, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x10000000000)) {
                                                                                            y := shr(32, y)
                                                                                            z := shl(16, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x1000000)) {
                                                                                            y := shr(16, y)
                                                                                            z := shl(8, z)
                                                                                        }
                                                                                        // Goal was to get z*z*y within a small factor of x. More iterations could
                                                                                        // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
                                                                                        // We ensured y >= 256 so that the relative difference between y and y+1 is small.
                                                                                        // That's not possible if x < 256 but we can just verify those cases exhaustively.
                                                                                        // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
                                                                                        // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
                                                                                        // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
                                                                                        // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
                                                                                        // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
                                                                                        // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
                                                                                        // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
                                                                                        // There is no overflow risk here since y < 2^136 after the first branch above.
                                                                                        z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
                                                                                        // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        // If x+1 is a perfect square, the Babylonian method cycles between
                                                                                        // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
                                                                                        // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
                                                                                        // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
                                                                                        // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
                                                                                        z := sub(z, lt(div(x, z), z))
                                                                                    }
                                                                                }
                                                                                function log2(uint256 x) internal pure returns (uint256 r) {
                                                                                    require(x > 0, "UNDEFINED");
                                                                                    assembly {
                                                                                        r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
                                                                                        r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
                                                                                        r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
                                                                                        r := or(r, shl(4, lt(0xffff, shr(r, x))))
                                                                                        r := or(r, shl(3, lt(0xff, shr(r, x))))
                                                                                        r := or(r, shl(2, lt(0xf, shr(r, x))))
                                                                                        r := or(r, shl(1, lt(0x3, shr(r, x))))
                                                                                        r := or(r, lt(0x1, shr(r, x)))
                                                                                    }
                                                                                }
                                                                            }
                                                                            

                                                                            File 7 of 10: Proxy
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { Constants } from "../libraries/Constants.sol";
                                                                            /// @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 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 {
                                                                                    bytes32 proxyImplementation = Constants.PROXY_IMPLEMENTATION_ADDRESS;
                                                                                    assembly {
                                                                                        sstore(proxyImplementation, _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();
                                                                                    bytes32 proxyOwner = Constants.PROXY_OWNER_ADDRESS;
                                                                                    assembly {
                                                                                        sstore(proxyOwner, _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;
                                                                                    bytes32 proxyImplementation = Constants.PROXY_IMPLEMENTATION_ADDRESS;
                                                                                    assembly {
                                                                                        impl := sload(proxyImplementation)
                                                                                    }
                                                                                    return impl;
                                                                                }
                                                                                /// @notice Queries the owner of the proxy contract.
                                                                                /// @return Owner address.
                                                                                function _getAdmin() internal view returns (address) {
                                                                                    address owner;
                                                                                    bytes32 proxyOwner = Constants.PROXY_OWNER_ADDRESS;
                                                                                    assembly {
                                                                                        owner := sload(proxyOwner)
                                                                                    }
                                                                                    return owner;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity ^0.8.0;
                                                                            import { ResourceMetering } from "../L1/ResourceMetering.sol";
                                                                            /// @title Constants
                                                                            /// @notice Constants is a library for storing constants. Simple! Don't put everything in here, just
                                                                            ///         the stuff used in multiple contracts. Constants that only apply to a single contract
                                                                            ///         should be defined in that contract instead.
                                                                            library Constants {
                                                                                /// @notice Special address to be used as the tx origin for gas estimation calls in the
                                                                                ///         OptimismPortal and CrossDomainMessenger calls. You only need to use this address if
                                                                                ///         the minimum gas limit specified by the user is not actually enough to execute the
                                                                                ///         given message and you're attempting to estimate the actual necessary gas limit. We
                                                                                ///         use address(1) because it's the ecrecover precompile and therefore guaranteed to
                                                                                ///         never have any code on any EVM chain.
                                                                                address internal constant ESTIMATION_ADDRESS = address(1);
                                                                                /// @notice Value used for the L2 sender storage slot in both the OptimismPortal and the
                                                                                ///         CrossDomainMessenger contracts before an actual sender is set. This value is
                                                                                ///         non-zero to reduce the gas cost of message passing transactions.
                                                                                address internal constant DEFAULT_L2_SENDER = 0x000000000000000000000000000000000000dEaD;
                                                                                /// @notice The storage slot that holds the address of a proxy implementation.
                                                                                /// @dev `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)`
                                                                                bytes32 internal constant PROXY_IMPLEMENTATION_ADDRESS =
                                                                                    0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                                                                                /// @notice The storage slot that holds the address of the owner.
                                                                                /// @dev `bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)`
                                                                                bytes32 internal constant PROXY_OWNER_ADDRESS = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                                                                                /// @notice Returns the default values for the ResourceConfig. These are the recommended values
                                                                                ///         for a production network.
                                                                                function DEFAULT_RESOURCE_CONFIG() internal pure returns (ResourceMetering.ResourceConfig memory) {
                                                                                    ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({
                                                                                        maxResourceLimit: 20_000_000,
                                                                                        elasticityMultiplier: 10,
                                                                                        baseFeeMaxChangeDenominator: 8,
                                                                                        minimumBaseFee: 1 gwei,
                                                                                        systemTxMaxGas: 1_000_000,
                                                                                        maximumBaseFee: type(uint128).max
                                                                                    });
                                                                                    return config;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
                                                                            import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
                                                                            import { Burn } from "../libraries/Burn.sol";
                                                                            import { Arithmetic } from "../libraries/Arithmetic.sol";
                                                                            /// @custom:upgradeable
                                                                            /// @title ResourceMetering
                                                                            /// @notice ResourceMetering implements an EIP-1559 style resource metering system where pricing
                                                                            ///         updates automatically based on current demand.
                                                                            abstract contract ResourceMetering is Initializable {
                                                                                /// @notice Represents the various parameters that control the way in which resources are
                                                                                ///         metered. Corresponds to the EIP-1559 resource metering system.
                                                                                /// @custom:field prevBaseFee   Base fee from the previous block(s).
                                                                                /// @custom:field prevBoughtGas Amount of gas bought so far in the current block.
                                                                                /// @custom:field prevBlockNum  Last block number that the base fee was updated.
                                                                                struct ResourceParams {
                                                                                    uint128 prevBaseFee;
                                                                                    uint64 prevBoughtGas;
                                                                                    uint64 prevBlockNum;
                                                                                }
                                                                                /// @notice Represents the configuration for the EIP-1559 based curve for the deposit gas
                                                                                ///         market. These values should be set with care as it is possible to set them in
                                                                                ///         a way that breaks the deposit gas market. The target resource limit is defined as
                                                                                ///         maxResourceLimit / elasticityMultiplier. This struct was designed to fit within a
                                                                                ///         single word. There is additional space for additions in the future.
                                                                                /// @custom:field maxResourceLimit             Represents the maximum amount of deposit gas that
                                                                                ///                                            can be purchased per block.
                                                                                /// @custom:field elasticityMultiplier         Determines the target resource limit along with
                                                                                ///                                            the resource limit.
                                                                                /// @custom:field baseFeeMaxChangeDenominator  Determines max change on fee per block.
                                                                                /// @custom:field minimumBaseFee               The min deposit base fee, it is clamped to this
                                                                                ///                                            value.
                                                                                /// @custom:field systemTxMaxGas               The amount of gas supplied to the system
                                                                                ///                                            transaction. This should be set to the same
                                                                                ///                                            number that the op-node sets as the gas limit
                                                                                ///                                            for the system transaction.
                                                                                /// @custom:field maximumBaseFee               The max deposit base fee, it is clamped to this
                                                                                ///                                            value.
                                                                                struct ResourceConfig {
                                                                                    uint32 maxResourceLimit;
                                                                                    uint8 elasticityMultiplier;
                                                                                    uint8 baseFeeMaxChangeDenominator;
                                                                                    uint32 minimumBaseFee;
                                                                                    uint32 systemTxMaxGas;
                                                                                    uint128 maximumBaseFee;
                                                                                }
                                                                                /// @notice EIP-1559 style gas parameters.
                                                                                ResourceParams public params;
                                                                                /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades.
                                                                                uint256[48] private __gap;
                                                                                /// @notice Meters access to a function based an amount of a requested resource.
                                                                                /// @param _amount Amount of the resource requested.
                                                                                modifier metered(uint64 _amount) {
                                                                                    // Record initial gas amount so we can refund for it later.
                                                                                    uint256 initialGas = gasleft();
                                                                                    // Run the underlying function.
                                                                                    _;
                                                                                    // Run the metering function.
                                                                                    _metered(_amount, initialGas);
                                                                                }
                                                                                /// @notice An internal function that holds all of the logic for metering a resource.
                                                                                /// @param _amount     Amount of the resource requested.
                                                                                /// @param _initialGas The amount of gas before any modifier execution.
                                                                                function _metered(uint64 _amount, uint256 _initialGas) internal {
                                                                                    // Update block number and base fee if necessary.
                                                                                    uint256 blockDiff = block.number - params.prevBlockNum;
                                                                                    ResourceConfig memory config = _resourceConfig();
                                                                                    int256 targetResourceLimit =
                                                                                        int256(uint256(config.maxResourceLimit)) / int256(uint256(config.elasticityMultiplier));
                                                                                    if (blockDiff > 0) {
                                                                                        // Handle updating EIP-1559 style gas parameters. We use EIP-1559 to restrict the rate
                                                                                        // at which deposits can be created and therefore limit the potential for deposits to
                                                                                        // spam the L2 system. Fee scheme is very similar to EIP-1559 with minor changes.
                                                                                        int256 gasUsedDelta = int256(uint256(params.prevBoughtGas)) - targetResourceLimit;
                                                                                        int256 baseFeeDelta = (int256(uint256(params.prevBaseFee)) * gasUsedDelta)
                                                                                            / (targetResourceLimit * int256(uint256(config.baseFeeMaxChangeDenominator)));
                                                                                        // Update base fee by adding the base fee delta and clamp the resulting value between
                                                                                        // min and max.
                                                                                        int256 newBaseFee = Arithmetic.clamp({
                                                                                            _value: int256(uint256(params.prevBaseFee)) + baseFeeDelta,
                                                                                            _min: int256(uint256(config.minimumBaseFee)),
                                                                                            _max: int256(uint256(config.maximumBaseFee))
                                                                                        });
                                                                                        // If we skipped more than one block, we also need to account for every empty block.
                                                                                        // Empty block means there was no demand for deposits in that block, so we should
                                                                                        // reflect this lack of demand in the fee.
                                                                                        if (blockDiff > 1) {
                                                                                            // Update the base fee by repeatedly applying the exponent 1-(1/change_denominator)
                                                                                            // blockDiff - 1 times. Simulates multiple empty blocks. Clamp the resulting value
                                                                                            // between min and max.
                                                                                            newBaseFee = Arithmetic.clamp({
                                                                                                _value: Arithmetic.cdexp({
                                                                                                    _coefficient: newBaseFee,
                                                                                                    _denominator: int256(uint256(config.baseFeeMaxChangeDenominator)),
                                                                                                    _exponent: int256(blockDiff - 1)
                                                                                                }),
                                                                                                _min: int256(uint256(config.minimumBaseFee)),
                                                                                                _max: int256(uint256(config.maximumBaseFee))
                                                                                            });
                                                                                        }
                                                                                        // Update new base fee, reset bought gas, and update block number.
                                                                                        params.prevBaseFee = uint128(uint256(newBaseFee));
                                                                                        params.prevBoughtGas = 0;
                                                                                        params.prevBlockNum = uint64(block.number);
                                                                                    }
                                                                                    // Make sure we can actually buy the resource amount requested by the user.
                                                                                    params.prevBoughtGas += _amount;
                                                                                    require(
                                                                                        int256(uint256(params.prevBoughtGas)) <= int256(uint256(config.maxResourceLimit)),
                                                                                        "ResourceMetering: cannot buy more gas than available gas limit"
                                                                                    );
                                                                                    // Determine the amount of ETH to be paid.
                                                                                    uint256 resourceCost = uint256(_amount) * uint256(params.prevBaseFee);
                                                                                    // We currently charge for this ETH amount as an L1 gas burn, so we convert the ETH amount
                                                                                    // into gas by dividing by the L1 base fee. We assume a minimum base fee of 1 gwei to avoid
                                                                                    // division by zero for L1s that don't support 1559 or to avoid excessive gas burns during
                                                                                    // periods of extremely low L1 demand. One-day average gas fee hasn't dipped below 1 gwei
                                                                                    // during any 1 day period in the last 5 years, so should be fine.
                                                                                    uint256 gasCost = resourceCost / Math.max(block.basefee, 1 gwei);
                                                                                    // Give the user a refund based on the amount of gas they used to do all of the work up to
                                                                                    // this point. Since we're at the end of the modifier, this should be pretty accurate. Acts
                                                                                    // effectively like a dynamic stipend (with a minimum value).
                                                                                    uint256 usedGas = _initialGas - gasleft();
                                                                                    if (gasCost > usedGas) {
                                                                                        Burn.gas(gasCost - usedGas);
                                                                                    }
                                                                                }
                                                                                /// @notice Virtual function that returns the resource config.
                                                                                ///         Contracts that inherit this contract must implement this function.
                                                                                /// @return ResourceConfig
                                                                                function _resourceConfig() internal virtual returns (ResourceConfig memory);
                                                                                /// @notice Sets initial resource parameter values.
                                                                                ///         This function must either be called by the initializer function of an upgradeable
                                                                                ///         child contract.
                                                                                // solhint-disable-next-line func-name-mixedcase
                                                                                function __ResourceMetering_init() internal onlyInitializing {
                                                                                    params = ResourceParams({ prevBaseFee: 1 gwei, prevBoughtGas: 0, prevBlockNum: uint64(block.number) });
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
                                                                            pragma solidity ^0.8.2;
                                                                            import "../../utils/Address.sol";
                                                                            /**
                                                                             * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                                                                             * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
                                                                             * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                                                                             * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                                                                             *
                                                                             * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
                                                                             * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
                                                                             * case an upgrade adds a module that needs to be initialized.
                                                                             *
                                                                             * For example:
                                                                             *
                                                                             * [.hljs-theme-light.nopadding]
                                                                             * ```
                                                                             * contract MyToken is ERC20Upgradeable {
                                                                             *     function initialize() initializer public {
                                                                             *         __ERC20_init("MyToken", "MTK");
                                                                             *     }
                                                                             * }
                                                                             * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
                                                                             *     function initializeV2() reinitializer(2) public {
                                                                             *         __ERC20Permit_init("MyToken");
                                                                             *     }
                                                                             * }
                                                                             * ```
                                                                             *
                                                                             * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                                                                             * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                                                                             *
                                                                             * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                                                                             * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                                                                             *
                                                                             * [CAUTION]
                                                                             * ====
                                                                             * Avoid leaving a contract uninitialized.
                                                                             *
                                                                             * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                                                                             * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
                                                                             * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
                                                                             *
                                                                             * [.hljs-theme-light.nopadding]
                                                                             * ```
                                                                             * /// @custom:oz-upgrades-unsafe-allow constructor
                                                                             * constructor() {
                                                                             *     _disableInitializers();
                                                                             * }
                                                                             * ```
                                                                             * ====
                                                                             */
                                                                            abstract contract Initializable {
                                                                                /**
                                                                                 * @dev Indicates that the contract has been initialized.
                                                                                 * @custom:oz-retyped-from bool
                                                                                 */
                                                                                uint8 private _initialized;
                                                                                /**
                                                                                 * @dev Indicates that the contract is in the process of being initialized.
                                                                                 */
                                                                                bool private _initializing;
                                                                                /**
                                                                                 * @dev Triggered when the contract has been initialized or reinitialized.
                                                                                 */
                                                                                event Initialized(uint8 version);
                                                                                /**
                                                                                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                                                                                 * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
                                                                                 */
                                                                                modifier initializer() {
                                                                                    bool isTopLevelCall = !_initializing;
                                                                                    require(
                                                                                        (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
                                                                                        "Initializable: contract is already initialized"
                                                                                    );
                                                                                    _initialized = 1;
                                                                                    if (isTopLevelCall) {
                                                                                        _initializing = true;
                                                                                    }
                                                                                    _;
                                                                                    if (isTopLevelCall) {
                                                                                        _initializing = false;
                                                                                        emit Initialized(1);
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                                                                                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                                                                                 * used to initialize parent contracts.
                                                                                 *
                                                                                 * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
                                                                                 * initialization step. This is essential to configure modules that are added through upgrades and that require
                                                                                 * initialization.
                                                                                 *
                                                                                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                                                                                 * a contract, executing them in the right order is up to the developer or operator.
                                                                                 */
                                                                                modifier reinitializer(uint8 version) {
                                                                                    require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                                                                                    _initialized = version;
                                                                                    _initializing = true;
                                                                                    _;
                                                                                    _initializing = false;
                                                                                    emit Initialized(version);
                                                                                }
                                                                                /**
                                                                                 * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                                                                                 * {initializer} and {reinitializer} modifiers, directly or indirectly.
                                                                                 */
                                                                                modifier onlyInitializing() {
                                                                                    require(_initializing, "Initializable: contract is not initializing");
                                                                                    _;
                                                                                }
                                                                                /**
                                                                                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                                                                                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                                                                                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                                                                                 * through proxies.
                                                                                 */
                                                                                function _disableInitializers() internal virtual {
                                                                                    require(!_initializing, "Initializable: contract is initializing");
                                                                                    if (_initialized < type(uint8).max) {
                                                                                        _initialized = type(uint8).max;
                                                                                        emit Initialized(type(uint8).max);
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
                                                                            pragma solidity ^0.8.0;
                                                                            /**
                                                                             * @dev Standard math utilities missing in the Solidity language.
                                                                             */
                                                                            library Math {
                                                                                enum Rounding {
                                                                                    Down, // Toward negative infinity
                                                                                    Up, // Toward infinity
                                                                                    Zero // Toward zero
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the largest of two numbers.
                                                                                 */
                                                                                function max(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    return a >= b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the smallest of two numbers.
                                                                                 */
                                                                                function min(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    return a < b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the average of two numbers. The result is rounded towards
                                                                                 * zero.
                                                                                 */
                                                                                function average(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    // (a + b) / 2 can overflow.
                                                                                    return (a & b) + (a ^ b) / 2;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the ceiling of the division of two numbers.
                                                                                 *
                                                                                 * This differs from standard division with `/` in that it rounds up instead
                                                                                 * of rounding down.
                                                                                 */
                                                                                function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    // (a + b - 1) / b can overflow on addition, so we distribute.
                                                                                    return a == 0 ? 0 : (a - 1) / b + 1;
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
                                                                                 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
                                                                                 * with further edits by Uniswap Labs also under MIT license.
                                                                                 */
                                                                                function mulDiv(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 result) {
                                                                                    unchecked {
                                                                                        // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                                                                                        // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                                                                                        // variables such that product = prod1 * 2^256 + prod0.
                                                                                        uint256 prod0; // Least significant 256 bits of the product
                                                                                        uint256 prod1; // Most significant 256 bits of the product
                                                                                        assembly {
                                                                                            let mm := mulmod(x, y, not(0))
                                                                                            prod0 := mul(x, y)
                                                                                            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                                                                                        }
                                                                                        // Handle non-overflow cases, 256 by 256 division.
                                                                                        if (prod1 == 0) {
                                                                                            return prod0 / denominator;
                                                                                        }
                                                                                        // Make sure the result is less than 2^256. Also prevents denominator == 0.
                                                                                        require(denominator > prod1);
                                                                                        ///////////////////////////////////////////////
                                                                                        // 512 by 256 division.
                                                                                        ///////////////////////////////////////////////
                                                                                        // Make division exact by subtracting the remainder from [prod1 prod0].
                                                                                        uint256 remainder;
                                                                                        assembly {
                                                                                            // Compute remainder using mulmod.
                                                                                            remainder := mulmod(x, y, denominator)
                                                                                            // Subtract 256 bit number from 512 bit number.
                                                                                            prod1 := sub(prod1, gt(remainder, prod0))
                                                                                            prod0 := sub(prod0, remainder)
                                                                                        }
                                                                                        // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                                                                                        // See https://cs.stackexchange.com/q/138556/92363.
                                                                                        // Does not overflow because the denominator cannot be zero at this stage in the function.
                                                                                        uint256 twos = denominator & (~denominator + 1);
                                                                                        assembly {
                                                                                            // Divide denominator by twos.
                                                                                            denominator := div(denominator, twos)
                                                                                            // Divide [prod1 prod0] by twos.
                                                                                            prod0 := div(prod0, twos)
                                                                                            // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                                                                                            twos := add(div(sub(0, twos), twos), 1)
                                                                                        }
                                                                                        // Shift in bits from prod1 into prod0.
                                                                                        prod0 |= prod1 * twos;
                                                                                        // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                                                                                        // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                                                                                        // four bits. That is, denominator * inv = 1 mod 2^4.
                                                                                        uint256 inverse = (3 * denominator) ^ 2;
                                                                                        // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                                                                                        // in modular arithmetic, doubling the correct bits in each step.
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^8
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^16
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^32
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^64
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^128
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^256
                                                                                        // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                                                                                        // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                                                                                        // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                                                                                        // is no longer required.
                                                                                        result = prod0 * inverse;
                                                                                        return result;
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
                                                                                 */
                                                                                function mulDiv(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator,
                                                                                    Rounding rounding
                                                                                ) internal pure returns (uint256) {
                                                                                    uint256 result = mulDiv(x, y, denominator);
                                                                                    if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                                                                                        result += 1;
                                                                                    }
                                                                                    return result;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
                                                                                 *
                                                                                 * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
                                                                                 */
                                                                                function sqrt(uint256 a) internal pure returns (uint256) {
                                                                                    if (a == 0) {
                                                                                        return 0;
                                                                                    }
                                                                                    // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                                                                                    // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                                                                                    // `msb(a) <= a < 2*msb(a)`.
                                                                                    // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
                                                                                    // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
                                                                                    // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
                                                                                    // good first aproximation of `sqrt(a)` with at least 1 correct bit.
                                                                                    uint256 result = 1;
                                                                                    uint256 x = a;
                                                                                    if (x >> 128 > 0) {
                                                                                        x >>= 128;
                                                                                        result <<= 64;
                                                                                    }
                                                                                    if (x >> 64 > 0) {
                                                                                        x >>= 64;
                                                                                        result <<= 32;
                                                                                    }
                                                                                    if (x >> 32 > 0) {
                                                                                        x >>= 32;
                                                                                        result <<= 16;
                                                                                    }
                                                                                    if (x >> 16 > 0) {
                                                                                        x >>= 16;
                                                                                        result <<= 8;
                                                                                    }
                                                                                    if (x >> 8 > 0) {
                                                                                        x >>= 8;
                                                                                        result <<= 4;
                                                                                    }
                                                                                    if (x >> 4 > 0) {
                                                                                        x >>= 4;
                                                                                        result <<= 2;
                                                                                    }
                                                                                    if (x >> 2 > 0) {
                                                                                        result <<= 1;
                                                                                    }
                                                                                    // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                                                                                    // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                                                                                    // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                                                                                    // into the expected uint128 result.
                                                                                    unchecked {
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        return min(result, a / result);
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates sqrt(a), following the selected rounding direction.
                                                                                 */
                                                                                function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                                                                                    uint256 result = sqrt(a);
                                                                                    if (rounding == Rounding.Up && result * result < a) {
                                                                                        result += 1;
                                                                                    }
                                                                                    return result;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            /// @title Burn
                                                                            /// @notice Utilities for burning stuff.
                                                                            library Burn {
                                                                                /// @notice Burns a given amount of ETH.
                                                                                /// @param _amount Amount of ETH to burn.
                                                                                function eth(uint256 _amount) internal {
                                                                                    new Burner{ value: _amount }();
                                                                                }
                                                                                /// @notice Burns a given amount of gas.
                                                                                /// @param _amount Amount of gas to burn.
                                                                                function gas(uint256 _amount) internal view {
                                                                                    uint256 i = 0;
                                                                                    uint256 initialGas = gasleft();
                                                                                    while (initialGas - gasleft() < _amount) {
                                                                                        ++i;
                                                                                    }
                                                                                }
                                                                            }
                                                                            /// @title Burner
                                                                            /// @notice Burner self-destructs on creation and sends all ETH to itself, removing all ETH given to
                                                                            ///         the contract from the circulating supply. Self-destructing is the only way to remove ETH
                                                                            ///         from the circulating supply.
                                                                            contract Burner {
                                                                                constructor() payable {
                                                                                    selfdestruct(payable(address(this)));
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { SignedMath } from "@openzeppelin/contracts/utils/math/SignedMath.sol";
                                                                            import { FixedPointMathLib } from "@rari-capital/solmate/src/utils/FixedPointMathLib.sol";
                                                                            /// @title Arithmetic
                                                                            /// @notice Even more math than before.
                                                                            library Arithmetic {
                                                                                /// @notice Clamps a value between a minimum and maximum.
                                                                                /// @param _value The value to clamp.
                                                                                /// @param _min   The minimum value.
                                                                                /// @param _max   The maximum value.
                                                                                /// @return The clamped value.
                                                                                function clamp(int256 _value, int256 _min, int256 _max) internal pure returns (int256) {
                                                                                    return SignedMath.min(SignedMath.max(_value, _min), _max);
                                                                                }
                                                                                /// @notice (c)oefficient (d)enominator (exp)onentiation function.
                                                                                ///         Returns the result of: c * (1 - 1/d)^exp.
                                                                                /// @param _coefficient Coefficient of the function.
                                                                                /// @param _denominator Fractional denominator.
                                                                                /// @param _exponent    Power function exponent.
                                                                                /// @return Result of c * (1 - 1/d)^exp.
                                                                                function cdexp(int256 _coefficient, int256 _denominator, int256 _exponent) internal pure returns (int256) {
                                                                                    return (_coefficient * (FixedPointMathLib.powWad(1e18 - (1e18 / _denominator), _exponent * 1e18))) / 1e18;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
                                                                            pragma solidity ^0.8.1;
                                                                            /**
                                                                             * @dev Collection of functions related to the address type
                                                                             */
                                                                            library Address {
                                                                                /**
                                                                                 * @dev Returns true if `account` is a contract.
                                                                                 *
                                                                                 * [IMPORTANT]
                                                                                 * ====
                                                                                 * It is unsafe to assume that an address for which this function returns
                                                                                 * false is an externally-owned account (EOA) and not a contract.
                                                                                 *
                                                                                 * Among others, `isContract` will return false for the following
                                                                                 * types of addresses:
                                                                                 *
                                                                                 *  - an externally-owned account
                                                                                 *  - a contract in construction
                                                                                 *  - an address where a contract will be created
                                                                                 *  - an address where a contract lived, but was destroyed
                                                                                 * ====
                                                                                 *
                                                                                 * [IMPORTANT]
                                                                                 * ====
                                                                                 * You shouldn't rely on `isContract` to protect against flash loan attacks!
                                                                                 *
                                                                                 * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                                                                                 * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                                                                                 * constructor.
                                                                                 * ====
                                                                                 */
                                                                                function isContract(address account) internal view returns (bool) {
                                                                                    // This method relies on extcodesize/address.code.length, which returns 0
                                                                                    // for contracts in construction, since the code is only stored at the end
                                                                                    // of the constructor execution.
                                                                                    return account.code.length > 0;
                                                                                }
                                                                                /**
                                                                                 * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                                                                                 * `recipient`, forwarding all available gas and reverting on errors.
                                                                                 *
                                                                                 * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                                                                                 * of certain opcodes, possibly making contracts go over the 2300 gas limit
                                                                                 * imposed by `transfer`, making them unable to receive funds via
                                                                                 * `transfer`. {sendValue} removes this limitation.
                                                                                 *
                                                                                 * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                                                                                 *
                                                                                 * IMPORTANT: because control is transferred to `recipient`, care must be
                                                                                 * taken to not create reentrancy vulnerabilities. Consider using
                                                                                 * {ReentrancyGuard} or the
                                                                                 * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                                                                                 */
                                                                                function sendValue(address payable recipient, uint256 amount) internal {
                                                                                    require(address(this).balance >= amount, "Address: insufficient balance");
                                                                                    (bool success, ) = recipient.call{value: amount}("");
                                                                                    require(success, "Address: unable to send value, recipient may have reverted");
                                                                                }
                                                                                /**
                                                                                 * @dev Performs a Solidity function call using a low level `call`. A
                                                                                 * plain `call` is an unsafe replacement for a function call: use this
                                                                                 * function instead.
                                                                                 *
                                                                                 * If `target` reverts with a revert reason, it is bubbled up by this
                                                                                 * function (like regular Solidity function calls).
                                                                                 *
                                                                                 * Returns the raw returned data. To convert to the expected return value,
                                                                                 * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                                                                                 *
                                                                                 * Requirements:
                                                                                 *
                                                                                 * - `target` must be a contract.
                                                                                 * - calling `target` with `data` must not revert.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                                                                    return functionCall(target, data, "Address: low-level call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                                                                                 * `errorMessage` as a fallback revert reason when `target` reverts.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    return functionCallWithValue(target, data, 0, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but also transferring `value` wei to `target`.
                                                                                 *
                                                                                 * Requirements:
                                                                                 *
                                                                                 * - the calling contract must have an ETH balance of at least `value`.
                                                                                 * - the called Solidity function must be `payable`.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCallWithValue(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    uint256 value
                                                                                ) internal returns (bytes memory) {
                                                                                    return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                                                                                 * with `errorMessage` as a fallback revert reason when `target` reverts.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCallWithValue(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    uint256 value,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    require(address(this).balance >= value, "Address: insufficient balance for call");
                                                                                    require(isContract(target), "Address: call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but performing a static call.
                                                                                 *
                                                                                 * _Available since v3.3._
                                                                                 */
                                                                                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                                                                    return functionStaticCall(target, data, "Address: low-level static call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                                                                                 * but performing a static call.
                                                                                 *
                                                                                 * _Available since v3.3._
                                                                                 */
                                                                                function functionStaticCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal view returns (bytes memory) {
                                                                                    require(isContract(target), "Address: static call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.staticcall(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but performing a delegate call.
                                                                                 *
                                                                                 * _Available since v3.4._
                                                                                 */
                                                                                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                                                                    return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                                                                                 * but performing a delegate call.
                                                                                 *
                                                                                 * _Available since v3.4._
                                                                                 */
                                                                                function functionDelegateCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    require(isContract(target), "Address: delegate call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.delegatecall(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                                                                                 * revert reason using the provided one.
                                                                                 *
                                                                                 * _Available since v4.3._
                                                                                 */
                                                                                function verifyCallResult(
                                                                                    bool success,
                                                                                    bytes memory returndata,
                                                                                    string memory errorMessage
                                                                                ) internal pure returns (bytes memory) {
                                                                                    if (success) {
                                                                                        return returndata;
                                                                                    } else {
                                                                                        // Look for revert reason and bubble it up if present
                                                                                        if (returndata.length > 0) {
                                                                                            // The easiest way to bubble the revert reason is using memory via assembly
                                                                                            /// @solidity memory-safe-assembly
                                                                                            assembly {
                                                                                                let returndata_size := mload(returndata)
                                                                                                revert(add(32, returndata), returndata_size)
                                                                                            }
                                                                                        } else {
                                                                                            revert(errorMessage);
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.5.0) (utils/math/SignedMath.sol)
                                                                            pragma solidity ^0.8.0;
                                                                            /**
                                                                             * @dev Standard signed math utilities missing in the Solidity language.
                                                                             */
                                                                            library SignedMath {
                                                                                /**
                                                                                 * @dev Returns the largest of two signed numbers.
                                                                                 */
                                                                                function max(int256 a, int256 b) internal pure returns (int256) {
                                                                                    return a >= b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the smallest of two signed numbers.
                                                                                 */
                                                                                function min(int256 a, int256 b) internal pure returns (int256) {
                                                                                    return a < b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the average of two signed numbers without overflow.
                                                                                 * The result is rounded towards zero.
                                                                                 */
                                                                                function average(int256 a, int256 b) internal pure returns (int256) {
                                                                                    // Formula from the book "Hacker's Delight"
                                                                                    int256 x = (a & b) + ((a ^ b) >> 1);
                                                                                    return x + (int256(uint256(x) >> 255) & (a ^ b));
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the absolute unsigned value of a signed value.
                                                                                 */
                                                                                function abs(int256 n) internal pure returns (uint256) {
                                                                                    unchecked {
                                                                                        // must be unchecked in order to support `n = type(int256).min`
                                                                                        return uint256(n >= 0 ? n : -n);
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >=0.8.0;
                                                                            /// @notice Arithmetic library with operations for fixed-point numbers.
                                                                            /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
                                                                            library FixedPointMathLib {
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                SIMPLIFIED FIXED POINT OPERATIONS
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
                                                                                function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
                                                                                }
                                                                                function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
                                                                                }
                                                                                function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
                                                                                }
                                                                                function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
                                                                                }
                                                                                function powWad(int256 x, int256 y) internal pure returns (int256) {
                                                                                    // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)
                                                                                    return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0.
                                                                                }
                                                                                function expWad(int256 x) internal pure returns (int256 r) {
                                                                                    unchecked {
                                                                                        // When the result is < 0.5 we return zero. This happens when
                                                                                        // x <= floor(log(0.5e18) * 1e18) ~ -42e18
                                                                                        if (x <= -42139678854452767551) return 0;
                                                                                        // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
                                                                                        // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
                                                                                        if (x >= 135305999368893231589) revert("EXP_OVERFLOW");
                                                                                        // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
                                                                                        // for more intermediate precision and a binary basis. This base conversion
                                                                                        // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
                                                                                        x = (x << 78) / 5**18;
                                                                                        // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
                                                                                        // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
                                                                                        // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
                                                                                        int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
                                                                                        x = x - k * 54916777467707473351141471128;
                                                                                        // k is in the range [-61, 195].
                                                                                        // Evaluate using a (6, 7)-term rational approximation.
                                                                                        // p is made monic, we'll multiply by a scale factor later.
                                                                                        int256 y = x + 1346386616545796478920950773328;
                                                                                        y = ((y * x) >> 96) + 57155421227552351082224309758442;
                                                                                        int256 p = y + x - 94201549194550492254356042504812;
                                                                                        p = ((p * y) >> 96) + 28719021644029726153956944680412240;
                                                                                        p = p * x + (4385272521454847904659076985693276 << 96);
                                                                                        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
                                                                                        int256 q = x - 2855989394907223263936484059900;
                                                                                        q = ((q * x) >> 96) + 50020603652535783019961831881945;
                                                                                        q = ((q * x) >> 96) - 533845033583426703283633433725380;
                                                                                        q = ((q * x) >> 96) + 3604857256930695427073651918091429;
                                                                                        q = ((q * x) >> 96) - 14423608567350463180887372962807573;
                                                                                        q = ((q * x) >> 96) + 26449188498355588339934803723976023;
                                                                                        assembly {
                                                                                            // Div in assembly because solidity adds a zero check despite the unchecked.
                                                                                            // The q polynomial won't have zeros in the domain as all its roots are complex.
                                                                                            // No scaling is necessary because p is already 2**96 too large.
                                                                                            r := sdiv(p, q)
                                                                                        }
                                                                                        // r should be in the range (0.09, 0.25) * 2**96.
                                                                                        // We now need to multiply r by:
                                                                                        // * the scale factor s = ~6.031367120.
                                                                                        // * the 2**k factor from the range reduction.
                                                                                        // * the 1e18 / 2**96 factor for base conversion.
                                                                                        // We do this all at once, with an intermediate result in 2**213
                                                                                        // basis, so the final right shift is always by a positive amount.
                                                                                        r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
                                                                                    }
                                                                                }
                                                                                function lnWad(int256 x) internal pure returns (int256 r) {
                                                                                    unchecked {
                                                                                        require(x > 0, "UNDEFINED");
                                                                                        // We want to convert x from 10**18 fixed point to 2**96 fixed point.
                                                                                        // We do this by multiplying by 2**96 / 10**18. But since
                                                                                        // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
                                                                                        // and add ln(2**96 / 10**18) at the end.
                                                                                        // Reduce range of x to (1, 2) * 2**96
                                                                                        // ln(2^k * x) = k * ln(2) + ln(x)
                                                                                        int256 k = int256(log2(uint256(x))) - 96;
                                                                                        x <<= uint256(159 - k);
                                                                                        x = int256(uint256(x) >> 159);
                                                                                        // Evaluate using a (8, 8)-term rational approximation.
                                                                                        // p is made monic, we will multiply by a scale factor later.
                                                                                        int256 p = x + 3273285459638523848632254066296;
                                                                                        p = ((p * x) >> 96) + 24828157081833163892658089445524;
                                                                                        p = ((p * x) >> 96) + 43456485725739037958740375743393;
                                                                                        p = ((p * x) >> 96) - 11111509109440967052023855526967;
                                                                                        p = ((p * x) >> 96) - 45023709667254063763336534515857;
                                                                                        p = ((p * x) >> 96) - 14706773417378608786704636184526;
                                                                                        p = p * x - (795164235651350426258249787498 << 96);
                                                                                        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
                                                                                        // q is monic by convention.
                                                                                        int256 q = x + 5573035233440673466300451813936;
                                                                                        q = ((q * x) >> 96) + 71694874799317883764090561454958;
                                                                                        q = ((q * x) >> 96) + 283447036172924575727196451306956;
                                                                                        q = ((q * x) >> 96) + 401686690394027663651624208769553;
                                                                                        q = ((q * x) >> 96) + 204048457590392012362485061816622;
                                                                                        q = ((q * x) >> 96) + 31853899698501571402653359427138;
                                                                                        q = ((q * x) >> 96) + 909429971244387300277376558375;
                                                                                        assembly {
                                                                                            // Div in assembly because solidity adds a zero check despite the unchecked.
                                                                                            // The q polynomial is known not to have zeros in the domain.
                                                                                            // No scaling required because p is already 2**96 too large.
                                                                                            r := sdiv(p, q)
                                                                                        }
                                                                                        // r is in the range (0, 0.125) * 2**96
                                                                                        // Finalization, we need to:
                                                                                        // * multiply by the scale factor s = 5.549…
                                                                                        // * add ln(2**96 / 10**18)
                                                                                        // * add k * ln(2)
                                                                                        // * multiply by 10**18 / 2**96 = 5**18 >> 78
                                                                                        // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
                                                                                        r *= 1677202110996718588342820967067443963516166;
                                                                                        // add ln(2) * k * 5e18 * 2**192
                                                                                        r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
                                                                                        // add ln(2**96 / 10**18) * 5e18 * 2**192
                                                                                        r += 600920179829731861736702779321621459595472258049074101567377883020018308;
                                                                                        // base conversion: mul 2**18 / 2**192
                                                                                        r >>= 174;
                                                                                    }
                                                                                }
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                LOW LEVEL FIXED POINT OPERATIONS
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                function mulDivDown(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        // Store x * y in z for now.
                                                                                        z := mul(x, y)
                                                                                        // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
                                                                                        if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                                                                                            revert(0, 0)
                                                                                        }
                                                                                        // Divide z by the denominator.
                                                                                        z := div(z, denominator)
                                                                                    }
                                                                                }
                                                                                function mulDivUp(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        // Store x * y in z for now.
                                                                                        z := mul(x, y)
                                                                                        // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
                                                                                        if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                                                                                            revert(0, 0)
                                                                                        }
                                                                                        // First, divide z - 1 by the denominator and add 1.
                                                                                        // We allow z - 1 to underflow if z is 0, because we multiply the
                                                                                        // end result by 0 if z is zero, ensuring we return 0 if z is zero.
                                                                                        z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
                                                                                    }
                                                                                }
                                                                                function rpow(
                                                                                    uint256 x,
                                                                                    uint256 n,
                                                                                    uint256 scalar
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        switch x
                                                                                        case 0 {
                                                                                            switch n
                                                                                            case 0 {
                                                                                                // 0 ** 0 = 1
                                                                                                z := scalar
                                                                                            }
                                                                                            default {
                                                                                                // 0 ** n = 0
                                                                                                z := 0
                                                                                            }
                                                                                        }
                                                                                        default {
                                                                                            switch mod(n, 2)
                                                                                            case 0 {
                                                                                                // If n is even, store scalar in z for now.
                                                                                                z := scalar
                                                                                            }
                                                                                            default {
                                                                                                // If n is odd, store x in z for now.
                                                                                                z := x
                                                                                            }
                                                                                            // Shifting right by 1 is like dividing by 2.
                                                                                            let half := shr(1, scalar)
                                                                                            for {
                                                                                                // Shift n right by 1 before looping to halve it.
                                                                                                n := shr(1, n)
                                                                                            } n {
                                                                                                // Shift n right by 1 each iteration to halve it.
                                                                                                n := shr(1, n)
                                                                                            } {
                                                                                                // Revert immediately if x ** 2 would overflow.
                                                                                                // Equivalent to iszero(eq(div(xx, x), x)) here.
                                                                                                if shr(128, x) {
                                                                                                    revert(0, 0)
                                                                                                }
                                                                                                // Store x squared.
                                                                                                let xx := mul(x, x)
                                                                                                // Round to the nearest number.
                                                                                                let xxRound := add(xx, half)
                                                                                                // Revert if xx + half overflowed.
                                                                                                if lt(xxRound, xx) {
                                                                                                    revert(0, 0)
                                                                                                }
                                                                                                // Set x to scaled xxRound.
                                                                                                x := div(xxRound, scalar)
                                                                                                // If n is even:
                                                                                                if mod(n, 2) {
                                                                                                    // Compute z * x.
                                                                                                    let zx := mul(z, x)
                                                                                                    // If z * x overflowed:
                                                                                                    if iszero(eq(div(zx, x), z)) {
                                                                                                        // Revert if x is non-zero.
                                                                                                        if iszero(iszero(x)) {
                                                                                                            revert(0, 0)
                                                                                                        }
                                                                                                    }
                                                                                                    // Round to the nearest number.
                                                                                                    let zxRound := add(zx, half)
                                                                                                    // Revert if zx + half overflowed.
                                                                                                    if lt(zxRound, zx) {
                                                                                                        revert(0, 0)
                                                                                                    }
                                                                                                    // Return properly scaled zxRound.
                                                                                                    z := div(zxRound, scalar)
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                    GENERAL NUMBER UTILITIES
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                function sqrt(uint256 x) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        let y := x // We start y at x, which will help us make our initial estimate.
                                                                                        z := 181 // The "correct" value is 1, but this saves a multiplication later.
                                                                                        // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
                                                                                        // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
                                                                                        // We check y >= 2^(k + 8) but shift right by k bits
                                                                                        // each branch to ensure that if x >= 256, then y >= 256.
                                                                                        if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                                                                                            y := shr(128, y)
                                                                                            z := shl(64, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x1000000000000000000)) {
                                                                                            y := shr(64, y)
                                                                                            z := shl(32, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x10000000000)) {
                                                                                            y := shr(32, y)
                                                                                            z := shl(16, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x1000000)) {
                                                                                            y := shr(16, y)
                                                                                            z := shl(8, z)
                                                                                        }
                                                                                        // Goal was to get z*z*y within a small factor of x. More iterations could
                                                                                        // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
                                                                                        // We ensured y >= 256 so that the relative difference between y and y+1 is small.
                                                                                        // That's not possible if x < 256 but we can just verify those cases exhaustively.
                                                                                        // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
                                                                                        // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
                                                                                        // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
                                                                                        // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
                                                                                        // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
                                                                                        // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
                                                                                        // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
                                                                                        // There is no overflow risk here since y < 2^136 after the first branch above.
                                                                                        z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
                                                                                        // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        // If x+1 is a perfect square, the Babylonian method cycles between
                                                                                        // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
                                                                                        // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
                                                                                        // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
                                                                                        // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
                                                                                        z := sub(z, lt(div(x, z), z))
                                                                                    }
                                                                                }
                                                                                function log2(uint256 x) internal pure returns (uint256 r) {
                                                                                    require(x > 0, "UNDEFINED");
                                                                                    assembly {
                                                                                        r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
                                                                                        r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
                                                                                        r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
                                                                                        r := or(r, shl(4, lt(0xffff, shr(r, x))))
                                                                                        r := or(r, shl(3, lt(0xff, shr(r, x))))
                                                                                        r := or(r, shl(2, lt(0xf, shr(r, x))))
                                                                                        r := or(r, shl(1, lt(0x3, shr(r, x))))
                                                                                        r := or(r, lt(0x1, shr(r, x)))
                                                                                    }
                                                                                }
                                                                            }
                                                                            

                                                                            File 8 of 10: Proxy
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { Constants } from "../libraries/Constants.sol";
                                                                            /// @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 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 {
                                                                                    bytes32 proxyImplementation = Constants.PROXY_IMPLEMENTATION_ADDRESS;
                                                                                    assembly {
                                                                                        sstore(proxyImplementation, _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();
                                                                                    bytes32 proxyOwner = Constants.PROXY_OWNER_ADDRESS;
                                                                                    assembly {
                                                                                        sstore(proxyOwner, _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;
                                                                                    bytes32 proxyImplementation = Constants.PROXY_IMPLEMENTATION_ADDRESS;
                                                                                    assembly {
                                                                                        impl := sload(proxyImplementation)
                                                                                    }
                                                                                    return impl;
                                                                                }
                                                                                /// @notice Queries the owner of the proxy contract.
                                                                                /// @return Owner address.
                                                                                function _getAdmin() internal view returns (address) {
                                                                                    address owner;
                                                                                    bytes32 proxyOwner = Constants.PROXY_OWNER_ADDRESS;
                                                                                    assembly {
                                                                                        owner := sload(proxyOwner)
                                                                                    }
                                                                                    return owner;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity ^0.8.0;
                                                                            import { ResourceMetering } from "../L1/ResourceMetering.sol";
                                                                            /// @title Constants
                                                                            /// @notice Constants is a library for storing constants. Simple! Don't put everything in here, just
                                                                            ///         the stuff used in multiple contracts. Constants that only apply to a single contract
                                                                            ///         should be defined in that contract instead.
                                                                            library Constants {
                                                                                /// @notice Special address to be used as the tx origin for gas estimation calls in the
                                                                                ///         OptimismPortal and CrossDomainMessenger calls. You only need to use this address if
                                                                                ///         the minimum gas limit specified by the user is not actually enough to execute the
                                                                                ///         given message and you're attempting to estimate the actual necessary gas limit. We
                                                                                ///         use address(1) because it's the ecrecover precompile and therefore guaranteed to
                                                                                ///         never have any code on any EVM chain.
                                                                                address internal constant ESTIMATION_ADDRESS = address(1);
                                                                                /// @notice Value used for the L2 sender storage slot in both the OptimismPortal and the
                                                                                ///         CrossDomainMessenger contracts before an actual sender is set. This value is
                                                                                ///         non-zero to reduce the gas cost of message passing transactions.
                                                                                address internal constant DEFAULT_L2_SENDER = 0x000000000000000000000000000000000000dEaD;
                                                                                /// @notice The storage slot that holds the address of a proxy implementation.
                                                                                /// @dev `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)`
                                                                                bytes32 internal constant PROXY_IMPLEMENTATION_ADDRESS =
                                                                                    0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                                                                                /// @notice The storage slot that holds the address of the owner.
                                                                                /// @dev `bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)`
                                                                                bytes32 internal constant PROXY_OWNER_ADDRESS = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                                                                                /// @notice Returns the default values for the ResourceConfig. These are the recommended values
                                                                                ///         for a production network.
                                                                                function DEFAULT_RESOURCE_CONFIG() internal pure returns (ResourceMetering.ResourceConfig memory) {
                                                                                    ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({
                                                                                        maxResourceLimit: 20_000_000,
                                                                                        elasticityMultiplier: 10,
                                                                                        baseFeeMaxChangeDenominator: 8,
                                                                                        minimumBaseFee: 1 gwei,
                                                                                        systemTxMaxGas: 1_000_000,
                                                                                        maximumBaseFee: type(uint128).max
                                                                                    });
                                                                                    return config;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
                                                                            import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
                                                                            import { Burn } from "../libraries/Burn.sol";
                                                                            import { Arithmetic } from "../libraries/Arithmetic.sol";
                                                                            /// @custom:upgradeable
                                                                            /// @title ResourceMetering
                                                                            /// @notice ResourceMetering implements an EIP-1559 style resource metering system where pricing
                                                                            ///         updates automatically based on current demand.
                                                                            abstract contract ResourceMetering is Initializable {
                                                                                /// @notice Represents the various parameters that control the way in which resources are
                                                                                ///         metered. Corresponds to the EIP-1559 resource metering system.
                                                                                /// @custom:field prevBaseFee   Base fee from the previous block(s).
                                                                                /// @custom:field prevBoughtGas Amount of gas bought so far in the current block.
                                                                                /// @custom:field prevBlockNum  Last block number that the base fee was updated.
                                                                                struct ResourceParams {
                                                                                    uint128 prevBaseFee;
                                                                                    uint64 prevBoughtGas;
                                                                                    uint64 prevBlockNum;
                                                                                }
                                                                                /// @notice Represents the configuration for the EIP-1559 based curve for the deposit gas
                                                                                ///         market. These values should be set with care as it is possible to set them in
                                                                                ///         a way that breaks the deposit gas market. The target resource limit is defined as
                                                                                ///         maxResourceLimit / elasticityMultiplier. This struct was designed to fit within a
                                                                                ///         single word. There is additional space for additions in the future.
                                                                                /// @custom:field maxResourceLimit             Represents the maximum amount of deposit gas that
                                                                                ///                                            can be purchased per block.
                                                                                /// @custom:field elasticityMultiplier         Determines the target resource limit along with
                                                                                ///                                            the resource limit.
                                                                                /// @custom:field baseFeeMaxChangeDenominator  Determines max change on fee per block.
                                                                                /// @custom:field minimumBaseFee               The min deposit base fee, it is clamped to this
                                                                                ///                                            value.
                                                                                /// @custom:field systemTxMaxGas               The amount of gas supplied to the system
                                                                                ///                                            transaction. This should be set to the same
                                                                                ///                                            number that the op-node sets as the gas limit
                                                                                ///                                            for the system transaction.
                                                                                /// @custom:field maximumBaseFee               The max deposit base fee, it is clamped to this
                                                                                ///                                            value.
                                                                                struct ResourceConfig {
                                                                                    uint32 maxResourceLimit;
                                                                                    uint8 elasticityMultiplier;
                                                                                    uint8 baseFeeMaxChangeDenominator;
                                                                                    uint32 minimumBaseFee;
                                                                                    uint32 systemTxMaxGas;
                                                                                    uint128 maximumBaseFee;
                                                                                }
                                                                                /// @notice EIP-1559 style gas parameters.
                                                                                ResourceParams public params;
                                                                                /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades.
                                                                                uint256[48] private __gap;
                                                                                /// @notice Meters access to a function based an amount of a requested resource.
                                                                                /// @param _amount Amount of the resource requested.
                                                                                modifier metered(uint64 _amount) {
                                                                                    // Record initial gas amount so we can refund for it later.
                                                                                    uint256 initialGas = gasleft();
                                                                                    // Run the underlying function.
                                                                                    _;
                                                                                    // Run the metering function.
                                                                                    _metered(_amount, initialGas);
                                                                                }
                                                                                /// @notice An internal function that holds all of the logic for metering a resource.
                                                                                /// @param _amount     Amount of the resource requested.
                                                                                /// @param _initialGas The amount of gas before any modifier execution.
                                                                                function _metered(uint64 _amount, uint256 _initialGas) internal {
                                                                                    // Update block number and base fee if necessary.
                                                                                    uint256 blockDiff = block.number - params.prevBlockNum;
                                                                                    ResourceConfig memory config = _resourceConfig();
                                                                                    int256 targetResourceLimit =
                                                                                        int256(uint256(config.maxResourceLimit)) / int256(uint256(config.elasticityMultiplier));
                                                                                    if (blockDiff > 0) {
                                                                                        // Handle updating EIP-1559 style gas parameters. We use EIP-1559 to restrict the rate
                                                                                        // at which deposits can be created and therefore limit the potential for deposits to
                                                                                        // spam the L2 system. Fee scheme is very similar to EIP-1559 with minor changes.
                                                                                        int256 gasUsedDelta = int256(uint256(params.prevBoughtGas)) - targetResourceLimit;
                                                                                        int256 baseFeeDelta = (int256(uint256(params.prevBaseFee)) * gasUsedDelta)
                                                                                            / (targetResourceLimit * int256(uint256(config.baseFeeMaxChangeDenominator)));
                                                                                        // Update base fee by adding the base fee delta and clamp the resulting value between
                                                                                        // min and max.
                                                                                        int256 newBaseFee = Arithmetic.clamp({
                                                                                            _value: int256(uint256(params.prevBaseFee)) + baseFeeDelta,
                                                                                            _min: int256(uint256(config.minimumBaseFee)),
                                                                                            _max: int256(uint256(config.maximumBaseFee))
                                                                                        });
                                                                                        // If we skipped more than one block, we also need to account for every empty block.
                                                                                        // Empty block means there was no demand for deposits in that block, so we should
                                                                                        // reflect this lack of demand in the fee.
                                                                                        if (blockDiff > 1) {
                                                                                            // Update the base fee by repeatedly applying the exponent 1-(1/change_denominator)
                                                                                            // blockDiff - 1 times. Simulates multiple empty blocks. Clamp the resulting value
                                                                                            // between min and max.
                                                                                            newBaseFee = Arithmetic.clamp({
                                                                                                _value: Arithmetic.cdexp({
                                                                                                    _coefficient: newBaseFee,
                                                                                                    _denominator: int256(uint256(config.baseFeeMaxChangeDenominator)),
                                                                                                    _exponent: int256(blockDiff - 1)
                                                                                                }),
                                                                                                _min: int256(uint256(config.minimumBaseFee)),
                                                                                                _max: int256(uint256(config.maximumBaseFee))
                                                                                            });
                                                                                        }
                                                                                        // Update new base fee, reset bought gas, and update block number.
                                                                                        params.prevBaseFee = uint128(uint256(newBaseFee));
                                                                                        params.prevBoughtGas = 0;
                                                                                        params.prevBlockNum = uint64(block.number);
                                                                                    }
                                                                                    // Make sure we can actually buy the resource amount requested by the user.
                                                                                    params.prevBoughtGas += _amount;
                                                                                    require(
                                                                                        int256(uint256(params.prevBoughtGas)) <= int256(uint256(config.maxResourceLimit)),
                                                                                        "ResourceMetering: cannot buy more gas than available gas limit"
                                                                                    );
                                                                                    // Determine the amount of ETH to be paid.
                                                                                    uint256 resourceCost = uint256(_amount) * uint256(params.prevBaseFee);
                                                                                    // We currently charge for this ETH amount as an L1 gas burn, so we convert the ETH amount
                                                                                    // into gas by dividing by the L1 base fee. We assume a minimum base fee of 1 gwei to avoid
                                                                                    // division by zero for L1s that don't support 1559 or to avoid excessive gas burns during
                                                                                    // periods of extremely low L1 demand. One-day average gas fee hasn't dipped below 1 gwei
                                                                                    // during any 1 day period in the last 5 years, so should be fine.
                                                                                    uint256 gasCost = resourceCost / Math.max(block.basefee, 1 gwei);
                                                                                    // Give the user a refund based on the amount of gas they used to do all of the work up to
                                                                                    // this point. Since we're at the end of the modifier, this should be pretty accurate. Acts
                                                                                    // effectively like a dynamic stipend (with a minimum value).
                                                                                    uint256 usedGas = _initialGas - gasleft();
                                                                                    if (gasCost > usedGas) {
                                                                                        Burn.gas(gasCost - usedGas);
                                                                                    }
                                                                                }
                                                                                /// @notice Virtual function that returns the resource config.
                                                                                ///         Contracts that inherit this contract must implement this function.
                                                                                /// @return ResourceConfig
                                                                                function _resourceConfig() internal virtual returns (ResourceConfig memory);
                                                                                /// @notice Sets initial resource parameter values.
                                                                                ///         This function must either be called by the initializer function of an upgradeable
                                                                                ///         child contract.
                                                                                // solhint-disable-next-line func-name-mixedcase
                                                                                function __ResourceMetering_init() internal onlyInitializing {
                                                                                    params = ResourceParams({ prevBaseFee: 1 gwei, prevBoughtGas: 0, prevBlockNum: uint64(block.number) });
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
                                                                            pragma solidity ^0.8.2;
                                                                            import "../../utils/Address.sol";
                                                                            /**
                                                                             * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                                                                             * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
                                                                             * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                                                                             * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                                                                             *
                                                                             * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
                                                                             * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
                                                                             * case an upgrade adds a module that needs to be initialized.
                                                                             *
                                                                             * For example:
                                                                             *
                                                                             * [.hljs-theme-light.nopadding]
                                                                             * ```
                                                                             * contract MyToken is ERC20Upgradeable {
                                                                             *     function initialize() initializer public {
                                                                             *         __ERC20_init("MyToken", "MTK");
                                                                             *     }
                                                                             * }
                                                                             * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
                                                                             *     function initializeV2() reinitializer(2) public {
                                                                             *         __ERC20Permit_init("MyToken");
                                                                             *     }
                                                                             * }
                                                                             * ```
                                                                             *
                                                                             * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                                                                             * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                                                                             *
                                                                             * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                                                                             * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                                                                             *
                                                                             * [CAUTION]
                                                                             * ====
                                                                             * Avoid leaving a contract uninitialized.
                                                                             *
                                                                             * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                                                                             * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
                                                                             * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
                                                                             *
                                                                             * [.hljs-theme-light.nopadding]
                                                                             * ```
                                                                             * /// @custom:oz-upgrades-unsafe-allow constructor
                                                                             * constructor() {
                                                                             *     _disableInitializers();
                                                                             * }
                                                                             * ```
                                                                             * ====
                                                                             */
                                                                            abstract contract Initializable {
                                                                                /**
                                                                                 * @dev Indicates that the contract has been initialized.
                                                                                 * @custom:oz-retyped-from bool
                                                                                 */
                                                                                uint8 private _initialized;
                                                                                /**
                                                                                 * @dev Indicates that the contract is in the process of being initialized.
                                                                                 */
                                                                                bool private _initializing;
                                                                                /**
                                                                                 * @dev Triggered when the contract has been initialized or reinitialized.
                                                                                 */
                                                                                event Initialized(uint8 version);
                                                                                /**
                                                                                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                                                                                 * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
                                                                                 */
                                                                                modifier initializer() {
                                                                                    bool isTopLevelCall = !_initializing;
                                                                                    require(
                                                                                        (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
                                                                                        "Initializable: contract is already initialized"
                                                                                    );
                                                                                    _initialized = 1;
                                                                                    if (isTopLevelCall) {
                                                                                        _initializing = true;
                                                                                    }
                                                                                    _;
                                                                                    if (isTopLevelCall) {
                                                                                        _initializing = false;
                                                                                        emit Initialized(1);
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                                                                                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                                                                                 * used to initialize parent contracts.
                                                                                 *
                                                                                 * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
                                                                                 * initialization step. This is essential to configure modules that are added through upgrades and that require
                                                                                 * initialization.
                                                                                 *
                                                                                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                                                                                 * a contract, executing them in the right order is up to the developer or operator.
                                                                                 */
                                                                                modifier reinitializer(uint8 version) {
                                                                                    require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                                                                                    _initialized = version;
                                                                                    _initializing = true;
                                                                                    _;
                                                                                    _initializing = false;
                                                                                    emit Initialized(version);
                                                                                }
                                                                                /**
                                                                                 * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                                                                                 * {initializer} and {reinitializer} modifiers, directly or indirectly.
                                                                                 */
                                                                                modifier onlyInitializing() {
                                                                                    require(_initializing, "Initializable: contract is not initializing");
                                                                                    _;
                                                                                }
                                                                                /**
                                                                                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                                                                                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                                                                                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                                                                                 * through proxies.
                                                                                 */
                                                                                function _disableInitializers() internal virtual {
                                                                                    require(!_initializing, "Initializable: contract is initializing");
                                                                                    if (_initialized < type(uint8).max) {
                                                                                        _initialized = type(uint8).max;
                                                                                        emit Initialized(type(uint8).max);
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
                                                                            pragma solidity ^0.8.0;
                                                                            /**
                                                                             * @dev Standard math utilities missing in the Solidity language.
                                                                             */
                                                                            library Math {
                                                                                enum Rounding {
                                                                                    Down, // Toward negative infinity
                                                                                    Up, // Toward infinity
                                                                                    Zero // Toward zero
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the largest of two numbers.
                                                                                 */
                                                                                function max(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    return a >= b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the smallest of two numbers.
                                                                                 */
                                                                                function min(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    return a < b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the average of two numbers. The result is rounded towards
                                                                                 * zero.
                                                                                 */
                                                                                function average(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    // (a + b) / 2 can overflow.
                                                                                    return (a & b) + (a ^ b) / 2;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the ceiling of the division of two numbers.
                                                                                 *
                                                                                 * This differs from standard division with `/` in that it rounds up instead
                                                                                 * of rounding down.
                                                                                 */
                                                                                function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                                                                                    // (a + b - 1) / b can overflow on addition, so we distribute.
                                                                                    return a == 0 ? 0 : (a - 1) / b + 1;
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
                                                                                 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
                                                                                 * with further edits by Uniswap Labs also under MIT license.
                                                                                 */
                                                                                function mulDiv(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 result) {
                                                                                    unchecked {
                                                                                        // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                                                                                        // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                                                                                        // variables such that product = prod1 * 2^256 + prod0.
                                                                                        uint256 prod0; // Least significant 256 bits of the product
                                                                                        uint256 prod1; // Most significant 256 bits of the product
                                                                                        assembly {
                                                                                            let mm := mulmod(x, y, not(0))
                                                                                            prod0 := mul(x, y)
                                                                                            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                                                                                        }
                                                                                        // Handle non-overflow cases, 256 by 256 division.
                                                                                        if (prod1 == 0) {
                                                                                            return prod0 / denominator;
                                                                                        }
                                                                                        // Make sure the result is less than 2^256. Also prevents denominator == 0.
                                                                                        require(denominator > prod1);
                                                                                        ///////////////////////////////////////////////
                                                                                        // 512 by 256 division.
                                                                                        ///////////////////////////////////////////////
                                                                                        // Make division exact by subtracting the remainder from [prod1 prod0].
                                                                                        uint256 remainder;
                                                                                        assembly {
                                                                                            // Compute remainder using mulmod.
                                                                                            remainder := mulmod(x, y, denominator)
                                                                                            // Subtract 256 bit number from 512 bit number.
                                                                                            prod1 := sub(prod1, gt(remainder, prod0))
                                                                                            prod0 := sub(prod0, remainder)
                                                                                        }
                                                                                        // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                                                                                        // See https://cs.stackexchange.com/q/138556/92363.
                                                                                        // Does not overflow because the denominator cannot be zero at this stage in the function.
                                                                                        uint256 twos = denominator & (~denominator + 1);
                                                                                        assembly {
                                                                                            // Divide denominator by twos.
                                                                                            denominator := div(denominator, twos)
                                                                                            // Divide [prod1 prod0] by twos.
                                                                                            prod0 := div(prod0, twos)
                                                                                            // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                                                                                            twos := add(div(sub(0, twos), twos), 1)
                                                                                        }
                                                                                        // Shift in bits from prod1 into prod0.
                                                                                        prod0 |= prod1 * twos;
                                                                                        // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                                                                                        // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                                                                                        // four bits. That is, denominator * inv = 1 mod 2^4.
                                                                                        uint256 inverse = (3 * denominator) ^ 2;
                                                                                        // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                                                                                        // in modular arithmetic, doubling the correct bits in each step.
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^8
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^16
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^32
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^64
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^128
                                                                                        inverse *= 2 - denominator * inverse; // inverse mod 2^256
                                                                                        // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                                                                                        // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                                                                                        // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                                                                                        // is no longer required.
                                                                                        result = prod0 * inverse;
                                                                                        return result;
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
                                                                                 */
                                                                                function mulDiv(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator,
                                                                                    Rounding rounding
                                                                                ) internal pure returns (uint256) {
                                                                                    uint256 result = mulDiv(x, y, denominator);
                                                                                    if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                                                                                        result += 1;
                                                                                    }
                                                                                    return result;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
                                                                                 *
                                                                                 * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
                                                                                 */
                                                                                function sqrt(uint256 a) internal pure returns (uint256) {
                                                                                    if (a == 0) {
                                                                                        return 0;
                                                                                    }
                                                                                    // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                                                                                    // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                                                                                    // `msb(a) <= a < 2*msb(a)`.
                                                                                    // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
                                                                                    // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
                                                                                    // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
                                                                                    // good first aproximation of `sqrt(a)` with at least 1 correct bit.
                                                                                    uint256 result = 1;
                                                                                    uint256 x = a;
                                                                                    if (x >> 128 > 0) {
                                                                                        x >>= 128;
                                                                                        result <<= 64;
                                                                                    }
                                                                                    if (x >> 64 > 0) {
                                                                                        x >>= 64;
                                                                                        result <<= 32;
                                                                                    }
                                                                                    if (x >> 32 > 0) {
                                                                                        x >>= 32;
                                                                                        result <<= 16;
                                                                                    }
                                                                                    if (x >> 16 > 0) {
                                                                                        x >>= 16;
                                                                                        result <<= 8;
                                                                                    }
                                                                                    if (x >> 8 > 0) {
                                                                                        x >>= 8;
                                                                                        result <<= 4;
                                                                                    }
                                                                                    if (x >> 4 > 0) {
                                                                                        x >>= 4;
                                                                                        result <<= 2;
                                                                                    }
                                                                                    if (x >> 2 > 0) {
                                                                                        result <<= 1;
                                                                                    }
                                                                                    // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                                                                                    // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                                                                                    // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                                                                                    // into the expected uint128 result.
                                                                                    unchecked {
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        result = (result + a / result) >> 1;
                                                                                        return min(result, a / result);
                                                                                    }
                                                                                }
                                                                                /**
                                                                                 * @notice Calculates sqrt(a), following the selected rounding direction.
                                                                                 */
                                                                                function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                                                                                    uint256 result = sqrt(a);
                                                                                    if (rounding == Rounding.Up && result * result < a) {
                                                                                        result += 1;
                                                                                    }
                                                                                    return result;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            /// @title Burn
                                                                            /// @notice Utilities for burning stuff.
                                                                            library Burn {
                                                                                /// @notice Burns a given amount of ETH.
                                                                                /// @param _amount Amount of ETH to burn.
                                                                                function eth(uint256 _amount) internal {
                                                                                    new Burner{ value: _amount }();
                                                                                }
                                                                                /// @notice Burns a given amount of gas.
                                                                                /// @param _amount Amount of gas to burn.
                                                                                function gas(uint256 _amount) internal view {
                                                                                    uint256 i = 0;
                                                                                    uint256 initialGas = gasleft();
                                                                                    while (initialGas - gasleft() < _amount) {
                                                                                        ++i;
                                                                                    }
                                                                                }
                                                                            }
                                                                            /// @title Burner
                                                                            /// @notice Burner self-destructs on creation and sends all ETH to itself, removing all ETH given to
                                                                            ///         the contract from the circulating supply. Self-destructing is the only way to remove ETH
                                                                            ///         from the circulating supply.
                                                                            contract Burner {
                                                                                constructor() payable {
                                                                                    selfdestruct(payable(address(this)));
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity 0.8.15;
                                                                            import { SignedMath } from "@openzeppelin/contracts/utils/math/SignedMath.sol";
                                                                            import { FixedPointMathLib } from "@rari-capital/solmate/src/utils/FixedPointMathLib.sol";
                                                                            /// @title Arithmetic
                                                                            /// @notice Even more math than before.
                                                                            library Arithmetic {
                                                                                /// @notice Clamps a value between a minimum and maximum.
                                                                                /// @param _value The value to clamp.
                                                                                /// @param _min   The minimum value.
                                                                                /// @param _max   The maximum value.
                                                                                /// @return The clamped value.
                                                                                function clamp(int256 _value, int256 _min, int256 _max) internal pure returns (int256) {
                                                                                    return SignedMath.min(SignedMath.max(_value, _min), _max);
                                                                                }
                                                                                /// @notice (c)oefficient (d)enominator (exp)onentiation function.
                                                                                ///         Returns the result of: c * (1 - 1/d)^exp.
                                                                                /// @param _coefficient Coefficient of the function.
                                                                                /// @param _denominator Fractional denominator.
                                                                                /// @param _exponent    Power function exponent.
                                                                                /// @return Result of c * (1 - 1/d)^exp.
                                                                                function cdexp(int256 _coefficient, int256 _denominator, int256 _exponent) internal pure returns (int256) {
                                                                                    return (_coefficient * (FixedPointMathLib.powWad(1e18 - (1e18 / _denominator), _exponent * 1e18))) / 1e18;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
                                                                            pragma solidity ^0.8.1;
                                                                            /**
                                                                             * @dev Collection of functions related to the address type
                                                                             */
                                                                            library Address {
                                                                                /**
                                                                                 * @dev Returns true if `account` is a contract.
                                                                                 *
                                                                                 * [IMPORTANT]
                                                                                 * ====
                                                                                 * It is unsafe to assume that an address for which this function returns
                                                                                 * false is an externally-owned account (EOA) and not a contract.
                                                                                 *
                                                                                 * Among others, `isContract` will return false for the following
                                                                                 * types of addresses:
                                                                                 *
                                                                                 *  - an externally-owned account
                                                                                 *  - a contract in construction
                                                                                 *  - an address where a contract will be created
                                                                                 *  - an address where a contract lived, but was destroyed
                                                                                 * ====
                                                                                 *
                                                                                 * [IMPORTANT]
                                                                                 * ====
                                                                                 * You shouldn't rely on `isContract` to protect against flash loan attacks!
                                                                                 *
                                                                                 * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                                                                                 * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                                                                                 * constructor.
                                                                                 * ====
                                                                                 */
                                                                                function isContract(address account) internal view returns (bool) {
                                                                                    // This method relies on extcodesize/address.code.length, which returns 0
                                                                                    // for contracts in construction, since the code is only stored at the end
                                                                                    // of the constructor execution.
                                                                                    return account.code.length > 0;
                                                                                }
                                                                                /**
                                                                                 * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                                                                                 * `recipient`, forwarding all available gas and reverting on errors.
                                                                                 *
                                                                                 * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                                                                                 * of certain opcodes, possibly making contracts go over the 2300 gas limit
                                                                                 * imposed by `transfer`, making them unable to receive funds via
                                                                                 * `transfer`. {sendValue} removes this limitation.
                                                                                 *
                                                                                 * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                                                                                 *
                                                                                 * IMPORTANT: because control is transferred to `recipient`, care must be
                                                                                 * taken to not create reentrancy vulnerabilities. Consider using
                                                                                 * {ReentrancyGuard} or the
                                                                                 * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                                                                                 */
                                                                                function sendValue(address payable recipient, uint256 amount) internal {
                                                                                    require(address(this).balance >= amount, "Address: insufficient balance");
                                                                                    (bool success, ) = recipient.call{value: amount}("");
                                                                                    require(success, "Address: unable to send value, recipient may have reverted");
                                                                                }
                                                                                /**
                                                                                 * @dev Performs a Solidity function call using a low level `call`. A
                                                                                 * plain `call` is an unsafe replacement for a function call: use this
                                                                                 * function instead.
                                                                                 *
                                                                                 * If `target` reverts with a revert reason, it is bubbled up by this
                                                                                 * function (like regular Solidity function calls).
                                                                                 *
                                                                                 * Returns the raw returned data. To convert to the expected return value,
                                                                                 * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                                                                                 *
                                                                                 * Requirements:
                                                                                 *
                                                                                 * - `target` must be a contract.
                                                                                 * - calling `target` with `data` must not revert.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                                                                                    return functionCall(target, data, "Address: low-level call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                                                                                 * `errorMessage` as a fallback revert reason when `target` reverts.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    return functionCallWithValue(target, data, 0, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but also transferring `value` wei to `target`.
                                                                                 *
                                                                                 * Requirements:
                                                                                 *
                                                                                 * - the calling contract must have an ETH balance of at least `value`.
                                                                                 * - the called Solidity function must be `payable`.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCallWithValue(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    uint256 value
                                                                                ) internal returns (bytes memory) {
                                                                                    return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                                                                                 * with `errorMessage` as a fallback revert reason when `target` reverts.
                                                                                 *
                                                                                 * _Available since v3.1._
                                                                                 */
                                                                                function functionCallWithValue(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    uint256 value,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    require(address(this).balance >= value, "Address: insufficient balance for call");
                                                                                    require(isContract(target), "Address: call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but performing a static call.
                                                                                 *
                                                                                 * _Available since v3.3._
                                                                                 */
                                                                                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                                                                                    return functionStaticCall(target, data, "Address: low-level static call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                                                                                 * but performing a static call.
                                                                                 *
                                                                                 * _Available since v3.3._
                                                                                 */
                                                                                function functionStaticCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal view returns (bytes memory) {
                                                                                    require(isContract(target), "Address: static call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.staticcall(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                                                                                 * but performing a delegate call.
                                                                                 *
                                                                                 * _Available since v3.4._
                                                                                 */
                                                                                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                                                                                    return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                                                                                }
                                                                                /**
                                                                                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                                                                                 * but performing a delegate call.
                                                                                 *
                                                                                 * _Available since v3.4._
                                                                                 */
                                                                                function functionDelegateCall(
                                                                                    address target,
                                                                                    bytes memory data,
                                                                                    string memory errorMessage
                                                                                ) internal returns (bytes memory) {
                                                                                    require(isContract(target), "Address: delegate call to non-contract");
                                                                                    (bool success, bytes memory returndata) = target.delegatecall(data);
                                                                                    return verifyCallResult(success, returndata, errorMessage);
                                                                                }
                                                                                /**
                                                                                 * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                                                                                 * revert reason using the provided one.
                                                                                 *
                                                                                 * _Available since v4.3._
                                                                                 */
                                                                                function verifyCallResult(
                                                                                    bool success,
                                                                                    bytes memory returndata,
                                                                                    string memory errorMessage
                                                                                ) internal pure returns (bytes memory) {
                                                                                    if (success) {
                                                                                        return returndata;
                                                                                    } else {
                                                                                        // Look for revert reason and bubble it up if present
                                                                                        if (returndata.length > 0) {
                                                                                            // The easiest way to bubble the revert reason is using memory via assembly
                                                                                            /// @solidity memory-safe-assembly
                                                                                            assembly {
                                                                                                let returndata_size := mload(returndata)
                                                                                                revert(add(32, returndata), returndata_size)
                                                                                            }
                                                                                        } else {
                                                                                            revert(errorMessage);
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            // OpenZeppelin Contracts (last updated v4.5.0) (utils/math/SignedMath.sol)
                                                                            pragma solidity ^0.8.0;
                                                                            /**
                                                                             * @dev Standard signed math utilities missing in the Solidity language.
                                                                             */
                                                                            library SignedMath {
                                                                                /**
                                                                                 * @dev Returns the largest of two signed numbers.
                                                                                 */
                                                                                function max(int256 a, int256 b) internal pure returns (int256) {
                                                                                    return a >= b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the smallest of two signed numbers.
                                                                                 */
                                                                                function min(int256 a, int256 b) internal pure returns (int256) {
                                                                                    return a < b ? a : b;
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the average of two signed numbers without overflow.
                                                                                 * The result is rounded towards zero.
                                                                                 */
                                                                                function average(int256 a, int256 b) internal pure returns (int256) {
                                                                                    // Formula from the book "Hacker's Delight"
                                                                                    int256 x = (a & b) + ((a ^ b) >> 1);
                                                                                    return x + (int256(uint256(x) >> 255) & (a ^ b));
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the absolute unsigned value of a signed value.
                                                                                 */
                                                                                function abs(int256 n) internal pure returns (uint256) {
                                                                                    unchecked {
                                                                                        // must be unchecked in order to support `n = type(int256).min`
                                                                                        return uint256(n >= 0 ? n : -n);
                                                                                    }
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >=0.8.0;
                                                                            /// @notice Arithmetic library with operations for fixed-point numbers.
                                                                            /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
                                                                            library FixedPointMathLib {
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                SIMPLIFIED FIXED POINT OPERATIONS
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
                                                                                function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
                                                                                }
                                                                                function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
                                                                                }
                                                                                function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
                                                                                }
                                                                                function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
                                                                                    return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
                                                                                }
                                                                                function powWad(int256 x, int256 y) internal pure returns (int256) {
                                                                                    // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)
                                                                                    return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0.
                                                                                }
                                                                                function expWad(int256 x) internal pure returns (int256 r) {
                                                                                    unchecked {
                                                                                        // When the result is < 0.5 we return zero. This happens when
                                                                                        // x <= floor(log(0.5e18) * 1e18) ~ -42e18
                                                                                        if (x <= -42139678854452767551) return 0;
                                                                                        // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
                                                                                        // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
                                                                                        if (x >= 135305999368893231589) revert("EXP_OVERFLOW");
                                                                                        // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
                                                                                        // for more intermediate precision and a binary basis. This base conversion
                                                                                        // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
                                                                                        x = (x << 78) / 5**18;
                                                                                        // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
                                                                                        // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
                                                                                        // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
                                                                                        int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
                                                                                        x = x - k * 54916777467707473351141471128;
                                                                                        // k is in the range [-61, 195].
                                                                                        // Evaluate using a (6, 7)-term rational approximation.
                                                                                        // p is made monic, we'll multiply by a scale factor later.
                                                                                        int256 y = x + 1346386616545796478920950773328;
                                                                                        y = ((y * x) >> 96) + 57155421227552351082224309758442;
                                                                                        int256 p = y + x - 94201549194550492254356042504812;
                                                                                        p = ((p * y) >> 96) + 28719021644029726153956944680412240;
                                                                                        p = p * x + (4385272521454847904659076985693276 << 96);
                                                                                        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
                                                                                        int256 q = x - 2855989394907223263936484059900;
                                                                                        q = ((q * x) >> 96) + 50020603652535783019961831881945;
                                                                                        q = ((q * x) >> 96) - 533845033583426703283633433725380;
                                                                                        q = ((q * x) >> 96) + 3604857256930695427073651918091429;
                                                                                        q = ((q * x) >> 96) - 14423608567350463180887372962807573;
                                                                                        q = ((q * x) >> 96) + 26449188498355588339934803723976023;
                                                                                        assembly {
                                                                                            // Div in assembly because solidity adds a zero check despite the unchecked.
                                                                                            // The q polynomial won't have zeros in the domain as all its roots are complex.
                                                                                            // No scaling is necessary because p is already 2**96 too large.
                                                                                            r := sdiv(p, q)
                                                                                        }
                                                                                        // r should be in the range (0.09, 0.25) * 2**96.
                                                                                        // We now need to multiply r by:
                                                                                        // * the scale factor s = ~6.031367120.
                                                                                        // * the 2**k factor from the range reduction.
                                                                                        // * the 1e18 / 2**96 factor for base conversion.
                                                                                        // We do this all at once, with an intermediate result in 2**213
                                                                                        // basis, so the final right shift is always by a positive amount.
                                                                                        r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
                                                                                    }
                                                                                }
                                                                                function lnWad(int256 x) internal pure returns (int256 r) {
                                                                                    unchecked {
                                                                                        require(x > 0, "UNDEFINED");
                                                                                        // We want to convert x from 10**18 fixed point to 2**96 fixed point.
                                                                                        // We do this by multiplying by 2**96 / 10**18. But since
                                                                                        // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
                                                                                        // and add ln(2**96 / 10**18) at the end.
                                                                                        // Reduce range of x to (1, 2) * 2**96
                                                                                        // ln(2^k * x) = k * ln(2) + ln(x)
                                                                                        int256 k = int256(log2(uint256(x))) - 96;
                                                                                        x <<= uint256(159 - k);
                                                                                        x = int256(uint256(x) >> 159);
                                                                                        // Evaluate using a (8, 8)-term rational approximation.
                                                                                        // p is made monic, we will multiply by a scale factor later.
                                                                                        int256 p = x + 3273285459638523848632254066296;
                                                                                        p = ((p * x) >> 96) + 24828157081833163892658089445524;
                                                                                        p = ((p * x) >> 96) + 43456485725739037958740375743393;
                                                                                        p = ((p * x) >> 96) - 11111509109440967052023855526967;
                                                                                        p = ((p * x) >> 96) - 45023709667254063763336534515857;
                                                                                        p = ((p * x) >> 96) - 14706773417378608786704636184526;
                                                                                        p = p * x - (795164235651350426258249787498 << 96);
                                                                                        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
                                                                                        // q is monic by convention.
                                                                                        int256 q = x + 5573035233440673466300451813936;
                                                                                        q = ((q * x) >> 96) + 71694874799317883764090561454958;
                                                                                        q = ((q * x) >> 96) + 283447036172924575727196451306956;
                                                                                        q = ((q * x) >> 96) + 401686690394027663651624208769553;
                                                                                        q = ((q * x) >> 96) + 204048457590392012362485061816622;
                                                                                        q = ((q * x) >> 96) + 31853899698501571402653359427138;
                                                                                        q = ((q * x) >> 96) + 909429971244387300277376558375;
                                                                                        assembly {
                                                                                            // Div in assembly because solidity adds a zero check despite the unchecked.
                                                                                            // The q polynomial is known not to have zeros in the domain.
                                                                                            // No scaling required because p is already 2**96 too large.
                                                                                            r := sdiv(p, q)
                                                                                        }
                                                                                        // r is in the range (0, 0.125) * 2**96
                                                                                        // Finalization, we need to:
                                                                                        // * multiply by the scale factor s = 5.549…
                                                                                        // * add ln(2**96 / 10**18)
                                                                                        // * add k * ln(2)
                                                                                        // * multiply by 10**18 / 2**96 = 5**18 >> 78
                                                                                        // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
                                                                                        r *= 1677202110996718588342820967067443963516166;
                                                                                        // add ln(2) * k * 5e18 * 2**192
                                                                                        r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
                                                                                        // add ln(2**96 / 10**18) * 5e18 * 2**192
                                                                                        r += 600920179829731861736702779321621459595472258049074101567377883020018308;
                                                                                        // base conversion: mul 2**18 / 2**192
                                                                                        r >>= 174;
                                                                                    }
                                                                                }
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                LOW LEVEL FIXED POINT OPERATIONS
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                function mulDivDown(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        // Store x * y in z for now.
                                                                                        z := mul(x, y)
                                                                                        // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
                                                                                        if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                                                                                            revert(0, 0)
                                                                                        }
                                                                                        // Divide z by the denominator.
                                                                                        z := div(z, denominator)
                                                                                    }
                                                                                }
                                                                                function mulDivUp(
                                                                                    uint256 x,
                                                                                    uint256 y,
                                                                                    uint256 denominator
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        // Store x * y in z for now.
                                                                                        z := mul(x, y)
                                                                                        // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
                                                                                        if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                                                                                            revert(0, 0)
                                                                                        }
                                                                                        // First, divide z - 1 by the denominator and add 1.
                                                                                        // We allow z - 1 to underflow if z is 0, because we multiply the
                                                                                        // end result by 0 if z is zero, ensuring we return 0 if z is zero.
                                                                                        z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
                                                                                    }
                                                                                }
                                                                                function rpow(
                                                                                    uint256 x,
                                                                                    uint256 n,
                                                                                    uint256 scalar
                                                                                ) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        switch x
                                                                                        case 0 {
                                                                                            switch n
                                                                                            case 0 {
                                                                                                // 0 ** 0 = 1
                                                                                                z := scalar
                                                                                            }
                                                                                            default {
                                                                                                // 0 ** n = 0
                                                                                                z := 0
                                                                                            }
                                                                                        }
                                                                                        default {
                                                                                            switch mod(n, 2)
                                                                                            case 0 {
                                                                                                // If n is even, store scalar in z for now.
                                                                                                z := scalar
                                                                                            }
                                                                                            default {
                                                                                                // If n is odd, store x in z for now.
                                                                                                z := x
                                                                                            }
                                                                                            // Shifting right by 1 is like dividing by 2.
                                                                                            let half := shr(1, scalar)
                                                                                            for {
                                                                                                // Shift n right by 1 before looping to halve it.
                                                                                                n := shr(1, n)
                                                                                            } n {
                                                                                                // Shift n right by 1 each iteration to halve it.
                                                                                                n := shr(1, n)
                                                                                            } {
                                                                                                // Revert immediately if x ** 2 would overflow.
                                                                                                // Equivalent to iszero(eq(div(xx, x), x)) here.
                                                                                                if shr(128, x) {
                                                                                                    revert(0, 0)
                                                                                                }
                                                                                                // Store x squared.
                                                                                                let xx := mul(x, x)
                                                                                                // Round to the nearest number.
                                                                                                let xxRound := add(xx, half)
                                                                                                // Revert if xx + half overflowed.
                                                                                                if lt(xxRound, xx) {
                                                                                                    revert(0, 0)
                                                                                                }
                                                                                                // Set x to scaled xxRound.
                                                                                                x := div(xxRound, scalar)
                                                                                                // If n is even:
                                                                                                if mod(n, 2) {
                                                                                                    // Compute z * x.
                                                                                                    let zx := mul(z, x)
                                                                                                    // If z * x overflowed:
                                                                                                    if iszero(eq(div(zx, x), z)) {
                                                                                                        // Revert if x is non-zero.
                                                                                                        if iszero(iszero(x)) {
                                                                                                            revert(0, 0)
                                                                                                        }
                                                                                                    }
                                                                                                    // Round to the nearest number.
                                                                                                    let zxRound := add(zx, half)
                                                                                                    // Revert if zx + half overflowed.
                                                                                                    if lt(zxRound, zx) {
                                                                                                        revert(0, 0)
                                                                                                    }
                                                                                                    // Return properly scaled zxRound.
                                                                                                    z := div(zxRound, scalar)
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                                /*//////////////////////////////////////////////////////////////
                                                                                                    GENERAL NUMBER UTILITIES
                                                                                //////////////////////////////////////////////////////////////*/
                                                                                function sqrt(uint256 x) internal pure returns (uint256 z) {
                                                                                    assembly {
                                                                                        let y := x // We start y at x, which will help us make our initial estimate.
                                                                                        z := 181 // The "correct" value is 1, but this saves a multiplication later.
                                                                                        // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
                                                                                        // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
                                                                                        // We check y >= 2^(k + 8) but shift right by k bits
                                                                                        // each branch to ensure that if x >= 256, then y >= 256.
                                                                                        if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                                                                                            y := shr(128, y)
                                                                                            z := shl(64, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x1000000000000000000)) {
                                                                                            y := shr(64, y)
                                                                                            z := shl(32, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x10000000000)) {
                                                                                            y := shr(32, y)
                                                                                            z := shl(16, z)
                                                                                        }
                                                                                        if iszero(lt(y, 0x1000000)) {
                                                                                            y := shr(16, y)
                                                                                            z := shl(8, z)
                                                                                        }
                                                                                        // Goal was to get z*z*y within a small factor of x. More iterations could
                                                                                        // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
                                                                                        // We ensured y >= 256 so that the relative difference between y and y+1 is small.
                                                                                        // That's not possible if x < 256 but we can just verify those cases exhaustively.
                                                                                        // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
                                                                                        // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
                                                                                        // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
                                                                                        // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
                                                                                        // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
                                                                                        // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
                                                                                        // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
                                                                                        // There is no overflow risk here since y < 2^136 after the first branch above.
                                                                                        z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
                                                                                        // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        z := shr(1, add(z, div(x, z)))
                                                                                        // If x+1 is a perfect square, the Babylonian method cycles between
                                                                                        // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
                                                                                        // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
                                                                                        // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
                                                                                        // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
                                                                                        z := sub(z, lt(div(x, z), z))
                                                                                    }
                                                                                }
                                                                                function log2(uint256 x) internal pure returns (uint256 r) {
                                                                                    require(x > 0, "UNDEFINED");
                                                                                    assembly {
                                                                                        r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
                                                                                        r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
                                                                                        r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
                                                                                        r := or(r, shl(4, lt(0xffff, shr(r, x))))
                                                                                        r := or(r, shl(3, lt(0xff, shr(r, x))))
                                                                                        r := or(r, shl(2, lt(0xf, shr(r, x))))
                                                                                        r := or(r, shl(1, lt(0x3, shr(r, x))))
                                                                                        r := or(r, lt(0x1, shr(r, x)))
                                                                                    }
                                                                                }
                                                                            }
                                                                            

                                                                            File 9 of 10: Lib_AddressManager
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >=0.6.0 <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 () internal {
                                                                                    address msgSender = _msgSender();
                                                                                    _owner = msgSender;
                                                                                    emit OwnershipTransferred(address(0), msgSender);
                                                                                }
                                                                                /**
                                                                                 * @dev Returns the address of the current owner.
                                                                                 */
                                                                                function owner() public view virtual returns (address) {
                                                                                    return _owner;
                                                                                }
                                                                                /**
                                                                                 * @dev Throws if called by any account other than the owner.
                                                                                 */
                                                                                modifier onlyOwner() {
                                                                                    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 {
                                                                                    emit OwnershipTransferred(_owner, address(0));
                                                                                    _owner = 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");
                                                                                    emit OwnershipTransferred(_owner, newOwner);
                                                                                    _owner = newOwner;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >=0.6.0 <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 GSN 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 payable) {
                                                                                    return msg.sender;
                                                                                }
                                                                                function _msgData() internal view virtual returns (bytes memory) {
                                                                                    this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                                                                                    return msg.data;
                                                                                }
                                                                            }
                                                                            // SPDX-License-Identifier: MIT
                                                                            pragma solidity >0.5.0 <0.8.0;
                                                                            /* External Imports */
                                                                            import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
                                                                            /**
                                                                             * @title Lib_AddressManager
                                                                             */
                                                                            contract Lib_AddressManager is Ownable {
                                                                                /**********
                                                                                 * Events *
                                                                                 **********/
                                                                                event AddressSet(
                                                                                    string indexed _name,
                                                                                    address _newAddress,
                                                                                    address _oldAddress
                                                                                );
                                                                                /*************
                                                                                 * Variables *
                                                                                 *************/
                                                                                mapping (bytes32 => address) private addresses;
                                                                                /********************
                                                                                 * Public Functions *
                                                                                 ********************/
                                                                                /**
                                                                                 * 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
                                                                                    );
                                                                                }
                                                                                /**
                                                                                 * 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)];
                                                                                }
                                                                                /**********************
                                                                                 * Internal Functions *
                                                                                 **********************/
                                                                                /**
                                                                                 * 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));
                                                                                }
                                                                            }
                                                                            

                                                                            File 10 of 10: 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;
                                                                                }
                                                                            }