ETH Price: $1,976.93 (+0.75%)

Transaction Decoder

Block:
24479131 at Feb-17-2026 09:06:59 PM +UTC
Transaction Fee:
0.00001965381117 ETH $0.04
Gas Used:
277,557 Gas / 0.07081 Gwei

Emitted Events:

266 L1ChugSplashProxy.0x2ac69ee804d9a7a0984249f508dfab7cb2534b465b6ce1580f99a38ba9c5e631( 0x2ac69ee804d9a7a0984249f508dfab7cb2534b465b6ce1580f99a38ba9c5e631, 0x000000000000000000000000bcf8c5f6ed6c679e6a5a858f807f0c15535fb16d, 0x000000000000000000000000bcf8c5f6ed6c679e6a5a858f807f0c15535fb16d, 00000000000000000000000000000000000000000000000000864db6b547dc00, 0000000000000000000000000000000000000000000000000000000000000040, 000000000000000000000000000000000000000000000000000000000000000b, 7375706572627269646765000000000000000000000000000000000000000000 )
267 L1ChugSplashProxy.0x31b2166ff604fc5672ea5df08a78081d2bc6d746cadce880747f3643d819e83d( 0x31b2166ff604fc5672ea5df08a78081d2bc6d746cadce880747f3643d819e83d, 0x000000000000000000000000bcf8c5f6ed6c679e6a5a858f807f0c15535fb16d, 0x000000000000000000000000bcf8c5f6ed6c679e6a5a858f807f0c15535fb16d, 00000000000000000000000000000000000000000000000000864db6b547dc00, 0000000000000000000000000000000000000000000000000000000000000040, 000000000000000000000000000000000000000000000000000000000000000b, 7375706572627269646765000000000000000000000000000000000000000000 )
268 ResolvedDelegateProxy.0x4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c( 0x4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c, 0x8b8ae66c2e1cea89774f9cacfa8614b5597e487354b4b03007473edc59f6853d )
269 Proxy.0xdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b( 0xdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b, 0x8242a2458bc4cdebdd30326a23752b4de8f4812d3f30f34a8a528f90f5578b26, 0000000000000000000000000000000000000000000000000000000000000001 )

Account State Difference:

  Address   Before After State Difference Code
(quasarbuilder)
16.331172839703137603 Eth16.331173181450189879 Eth0.000000341747052276
0x758E0EE6...0fbb87812 2,646.487125501008592856 Eth2,646.449322407008592856 Eth0.037803094
0xBCF8c5F6...5535fb16D
0.004489488340606933 Eth
Nonce: 1059
0.042272928529436933 Eth
Nonce: 1060
0.03778344018883
0xe6a99Ef1...0E6903759

Execution Trace

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

                                                              File 3 of 8: ResolvedDelegateProxy
                                                              // SPDX-License-Identifier: MIT
                                                              pragma solidity 0.8.15;
                                                              import { AddressManager } from "./AddressManager.sol";
                                                              /**
                                                               * @custom:legacy
                                                               * @title ResolvedDelegateProxy
                                                               * @notice ResolvedDelegateProxy is a legacy proxy contract that makes use of the AddressManager to
                                                               *         resolve the implementation address. We're maintaining this contract for backwards
                                                               *         compatibility so we can manage all legacy proxies where necessary.
                                                               */
                                                              contract ResolvedDelegateProxy {
                                                                  /**
                                                                   * @notice Mapping used to store the implementation name that corresponds to this contract. A
                                                                   *         mapping was originally used as a way to bypass the same issue normally solved by
                                                                   *         storing the implementation address in a specific storage slot that does not conflict
                                                                   *         with any other storage slot. Generally NOT a safe solution but works as long as the
                                                                   *         implementation does not also keep a mapping in the first storage slot.
                                                                   */
                                                                  mapping(address => string) private implementationName;
                                                                  /**
                                                                   * @notice Mapping used to store the address of the AddressManager contract where the
                                                                   *         implementation address will be resolved from. Same concept here as with the above
                                                                   *         mapping. Also generally unsafe but fine if the implementation doesn't keep a mapping
                                                                   *         in the second storage slot.
                                                                   */
                                                                  mapping(address => AddressManager) private addressManager;
                                                                  /**
                                                                   * @param _addressManager  Address of the AddressManager.
                                                                   * @param _implementationName implementationName of the contract to proxy to.
                                                                   */
                                                                  constructor(AddressManager _addressManager, string memory _implementationName) {
                                                                      addressManager[address(this)] = _addressManager;
                                                                      implementationName[address(this)] = _implementationName;
                                                                  }
                                                                  /**
                                                                   * @notice Fallback, performs a delegatecall to the resolved implementation address.
                                                                   */
                                                                  // solhint-disable-next-line no-complex-fallback
                                                                  fallback() external payable {
                                                                      address target = addressManager[address(this)].getAddress(
                                                                          (implementationName[address(this)])
                                                                      );
                                                                      require(target != address(0), "ResolvedDelegateProxy: target address must be initialized");
                                                                      // slither-disable-next-line controlled-delegatecall
                                                                      (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))
                                                                          }
                                                                      }
                                                                  }
                                                              }
                                                              // 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
                                                              // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
                                                              pragma solidity ^0.8.0;
                                                              abstract contract Context {
                                                                  function _msgSender() internal view virtual returns (address) {
                                                                      return msg.sender;
                                                                  }
                                                                  function _msgData() internal view virtual returns (bytes calldata) {
                                                                      return msg.data;
                                                                  }
                                                              }
                                                              /**
                                                               * @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);
                                                                  }
                                                              }
                                                              

                                                              File 4 of 8: 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 5 of 8: 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 6 of 8: 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 8: AddressManager
                                                              // 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
                                                              // 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;
                                                                  }
                                                              }
                                                              

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