ETH Price: $2,670.52 (+1.35%)

Transaction Decoder

Block:
19867761 at May-14-2024 10:50:23 AM +UTC
Transaction Fee:
0.001284191598161472 ETH $3.43
Gas Used:
95,568 Gas / 13.437464404 Gwei

Emitted Events:

139 TransparentUpgradeableProxy.0x20af7f3bbfe38132b8900ae295cd9c8d1914be7052d061a511f3f728dab18964( 0x20af7f3bbfe38132b8900ae295cd9c8d1914be7052d061a511f3f728dab18964, 0x000000000000000000000000eb9b7b17cfdc1ac526722466dd82c4566413f237, 0x000000000000000000000000eb9b7b17cfdc1ac526722466dd82c4566413f237, 0x0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000000000000000000ce0b )
140 TransparentUpgradeableProxy.0x2d9d115ef3e4a606d698913b1eae831a3cdfe20d9a83d48007b0526749c3d466( 0x2d9d115ef3e4a606d698913b1eae831a3cdfe20d9a83d48007b0526749c3d466, 0x000000000000000000000000d4b80c3d7240325d18e645b49e6535a3bf95cc58, 0x000000000000000000000000eb9b7b17cfdc1ac526722466dd82c4566413f237, 0000000000000000000000000000000000000000000000000036538f3678afcb, 0000000000000000000000000000000000000000000000000000000000000040, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
(beaverbuild)
6.440693451814088473 Eth6.441362427814088473 Eth0.000668976
0xC1Ebd02f...7DdE276Bd
(Arbitrum Nova: Bridge)
14,068.198792577261076589 Eth14,068.183501053959393442 Eth0.015291523301683147
0xD4B80C3D...3Bf95cc58
(Arbitrum Nova: Outbox)
0xeB9B7b17...66413F237
0.014459519197050984 Eth
Nonce: 2
0.028466850900572659 Eth
Nonce: 3
0.014007331703521675

Execution Trace

TransparentUpgradeableProxy.08635a95( )
  • Outbox.executeTransaction( )
    • TransparentUpgradeableProxy.9e5d4c49( )
      • Bridge.executeCall( to=0xeB9B7b17cfdC1AC526722466Dd82c4566413F237, value=15291523301683147, data=0x ) => ( success=True, returnData=0x )
        • ETH 0.015291523301683147 0xeb9b7b17cfdc1ac526722466dd82c4566413f237.CALL( )
          executeTransaction[Outbox (ln:114)]
          File 1 of 4: TransparentUpgradeableProxy
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)
          pragma solidity ^0.8.0;
          import "../ERC1967/ERC1967Proxy.sol";
          /**
           * @dev This contract implements a proxy that is upgradeable by an admin.
           *
           * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
           * clashing], which can potentially be used in an attack, this contract uses the
           * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
           * things that go hand in hand:
           *
           * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
           * that call matches one of the admin functions exposed by the proxy itself.
           * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
           * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
           * "admin cannot fallback to proxy target".
           *
           * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
           * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
           * to sudden errors when trying to call a function from the proxy implementation.
           *
           * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
           * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
           */
          contract TransparentUpgradeableProxy is ERC1967Proxy {
              /**
               * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
               * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
               */
              constructor(
                  address _logic,
                  address admin_,
                  bytes memory _data
              ) payable ERC1967Proxy(_logic, _data) {
                  assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                  _changeAdmin(admin_);
              }
              /**
               * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
               */
              modifier ifAdmin() {
                  if (msg.sender == _getAdmin()) {
                      _;
                  } else {
                      _fallback();
                  }
              }
              /**
               * @dev Returns the current admin.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
               *
               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
               * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
               */
              function admin() external ifAdmin returns (address admin_) {
                  admin_ = _getAdmin();
              }
              /**
               * @dev Returns the current implementation.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
               *
               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
               * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
               */
              function implementation() external ifAdmin returns (address implementation_) {
                  implementation_ = _implementation();
              }
              /**
               * @dev Changes the admin of the proxy.
               *
               * Emits an {AdminChanged} event.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
               */
              function changeAdmin(address newAdmin) external virtual ifAdmin {
                  _changeAdmin(newAdmin);
              }
              /**
               * @dev Upgrade the implementation of the proxy.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
               */
              function upgradeTo(address newImplementation) external ifAdmin {
                  _upgradeToAndCall(newImplementation, bytes(""), false);
              }
              /**
               * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
               * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
               * proxied contract.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
               */
              function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                  _upgradeToAndCall(newImplementation, data, true);
              }
              /**
               * @dev Returns the current admin.
               */
              function _admin() internal view virtual returns (address) {
                  return _getAdmin();
              }
              /**
               * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
               */
              function _beforeFallback() internal virtual override {
                  require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                  super._beforeFallback();
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)
          pragma solidity ^0.8.0;
          import "../Proxy.sol";
          import "./ERC1967Upgrade.sol";
          /**
           * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
           * implementation address that can be changed. This address is stored in storage in the location specified by
           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
           * implementation behind the proxy.
           */
          contract ERC1967Proxy is Proxy, ERC1967Upgrade {
              /**
               * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
               *
               * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
               * function call, and allows initializating the storage of the proxy like a Solidity constructor.
               */
              constructor(address _logic, bytes memory _data) payable {
                  assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                  _upgradeToAndCall(_logic, _data, false);
              }
              /**
               * @dev Returns the current implementation address.
               */
              function _implementation() internal view virtual override returns (address impl) {
                  return ERC1967Upgrade._getImplementation();
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.0) (proxy/Proxy.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
           * be specified by overriding the virtual {_implementation} function.
           *
           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
           * different contract through the {_delegate} function.
           *
           * The success and return data of the delegated call will be returned back to the caller of the proxy.
           */
          abstract contract Proxy {
              /**
               * @dev Delegates the current call to `implementation`.
               *
               * This function does not return to its internal call site, it will return directly to the external caller.
               */
              function _delegate(address implementation) internal virtual {
                  assembly {
                      // Copy msg.data. We take full control of memory in this inline assembly
                      // block because it will not return to Solidity code. We overwrite the
                      // Solidity scratch pad at memory position 0.
                      calldatacopy(0, 0, calldatasize())
                      // Call the implementation.
                      // out and outsize are 0 because we don't know the size yet.
                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                      // Copy the returned data.
                      returndatacopy(0, 0, returndatasize())
                      switch result
                      // delegatecall returns 0 on error.
                      case 0 {
                          revert(0, returndatasize())
                      }
                      default {
                          return(0, returndatasize())
                      }
                  }
              }
              /**
               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
               * and {_fallback} should delegate.
               */
              function _implementation() internal view virtual returns (address);
              /**
               * @dev Delegates the current call to the address returned by `_implementation()`.
               *
               * This function does not return to its internall call site, it will return directly to the external caller.
               */
              function _fallback() internal virtual {
                  _beforeFallback();
                  _delegate(_implementation());
              }
              /**
               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
               * function in the contract matches the call data.
               */
              fallback() external payable virtual {
                  _fallback();
              }
              /**
               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
               * is empty.
               */
              receive() external payable virtual {
                  _fallback();
              }
              /**
               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
               * call, or as part of the Solidity `fallback` or `receive` functions.
               *
               * If overriden should call `super._beforeFallback()`.
               */
              function _beforeFallback() internal virtual {}
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
          pragma solidity ^0.8.2;
          import "../beacon/IBeacon.sol";
          import "../../interfaces/draft-IERC1822.sol";
          import "../../utils/Address.sol";
          import "../../utils/StorageSlot.sol";
          /**
           * @dev This abstract contract provides getters and event emitting update functions for
           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
           *
           * _Available since v4.1._
           *
           * @custom:oz-upgrades-unsafe-allow delegatecall
           */
          abstract contract ERC1967Upgrade {
              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
              /**
               * @dev Storage slot with the address of the current implementation.
               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
               * validated in the constructor.
               */
              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
              /**
               * @dev Emitted when the implementation is upgraded.
               */
              event Upgraded(address indexed implementation);
              /**
               * @dev Returns the current implementation address.
               */
              function _getImplementation() internal view returns (address) {
                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
              }
              /**
               * @dev Stores a new address in the EIP1967 implementation slot.
               */
              function _setImplementation(address newImplementation) private {
                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
              }
              /**
               * @dev Perform implementation upgrade
               *
               * Emits an {Upgraded} event.
               */
              function _upgradeTo(address newImplementation) internal {
                  _setImplementation(newImplementation);
                  emit Upgraded(newImplementation);
              }
              /**
               * @dev Perform implementation upgrade with additional setup call.
               *
               * Emits an {Upgraded} event.
               */
              function _upgradeToAndCall(
                  address newImplementation,
                  bytes memory data,
                  bool forceCall
              ) internal {
                  _upgradeTo(newImplementation);
                  if (data.length > 0 || forceCall) {
                      Address.functionDelegateCall(newImplementation, data);
                  }
              }
              /**
               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
               *
               * Emits an {Upgraded} event.
               */
              function _upgradeToAndCallUUPS(
                  address newImplementation,
                  bytes memory data,
                  bool forceCall
              ) internal {
                  // Upgrades from old implementations will perform a rollback test. This test requires the new
                  // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                  // this special case will break upgrade paths from old UUPS implementation to new ones.
                  if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
                      _setImplementation(newImplementation);
                  } else {
                      try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                          require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                      } catch {
                          revert("ERC1967Upgrade: new implementation is not UUPS");
                      }
                      _upgradeToAndCall(newImplementation, data, forceCall);
                  }
              }
              /**
               * @dev Storage slot with the admin of the contract.
               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
               * validated in the constructor.
               */
              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
              /**
               * @dev Emitted when the admin account has changed.
               */
              event AdminChanged(address previousAdmin, address newAdmin);
              /**
               * @dev Returns the current admin.
               */
              function _getAdmin() internal view returns (address) {
                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
              }
              /**
               * @dev Stores a new address in the EIP1967 admin slot.
               */
              function _setAdmin(address newAdmin) private {
                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
              }
              /**
               * @dev Changes the admin of the proxy.
               *
               * Emits an {AdminChanged} event.
               */
              function _changeAdmin(address newAdmin) internal {
                  emit AdminChanged(_getAdmin(), newAdmin);
                  _setAdmin(newAdmin);
              }
              /**
               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
               */
              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
              /**
               * @dev Emitted when the beacon is upgraded.
               */
              event BeaconUpgraded(address indexed beacon);
              /**
               * @dev Returns the current beacon.
               */
              function _getBeacon() internal view returns (address) {
                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
              }
              /**
               * @dev Stores a new beacon in the EIP1967 beacon slot.
               */
              function _setBeacon(address newBeacon) private {
                  require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                  require(
                      Address.isContract(IBeacon(newBeacon).implementation()),
                      "ERC1967: beacon implementation is not a contract"
                  );
                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
              }
              /**
               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
               *
               * Emits a {BeaconUpgraded} event.
               */
              function _upgradeBeaconToAndCall(
                  address newBeacon,
                  bytes memory data,
                  bool forceCall
              ) internal {
                  _setBeacon(newBeacon);
                  emit BeaconUpgraded(newBeacon);
                  if (data.length > 0 || forceCall) {
                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev This is the interface that {BeaconProxy} expects of its beacon.
           */
          interface IBeacon {
              /**
               * @dev Must return an address that can be used as a delegate call target.
               *
               * {BeaconProxy} will check that this address is a contract.
               */
              function implementation() external view returns (address);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
           * proxy whose upgrades are fully controlled by the current implementation.
           */
          interface IERC1822Proxiable {
              /**
               * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
               * address.
               *
               * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
               * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
               * function revert if invoked through a proxy.
               */
              function proxiableUUID() external view returns (bytes32);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.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
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Library for reading and writing primitive types to specific storage slots.
           *
           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
           * This library helps with reading and writing to such slots without the need for inline assembly.
           *
           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
           *
           * Example usage to set ERC1967 implementation slot:
           * ```
           * contract ERC1967 {
           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
           *
           *     function _getImplementation() internal view returns (address) {
           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
           *     }
           *
           *     function _setImplementation(address newImplementation) internal {
           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
           *     }
           * }
           * ```
           *
           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
           */
          library StorageSlot {
              struct AddressSlot {
                  address value;
              }
              struct BooleanSlot {
                  bool value;
              }
              struct Bytes32Slot {
                  bytes32 value;
              }
              struct Uint256Slot {
                  uint256 value;
              }
              /**
               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
               */
              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
               */
              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
               */
              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
               */
              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
          }
          

          File 2 of 4: TransparentUpgradeableProxy
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)
          pragma solidity ^0.8.0;
          import "../ERC1967/ERC1967Proxy.sol";
          /**
           * @dev This contract implements a proxy that is upgradeable by an admin.
           *
           * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
           * clashing], which can potentially be used in an attack, this contract uses the
           * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
           * things that go hand in hand:
           *
           * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
           * that call matches one of the admin functions exposed by the proxy itself.
           * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
           * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
           * "admin cannot fallback to proxy target".
           *
           * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
           * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
           * to sudden errors when trying to call a function from the proxy implementation.
           *
           * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
           * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
           */
          contract TransparentUpgradeableProxy is ERC1967Proxy {
              /**
               * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
               * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
               */
              constructor(
                  address _logic,
                  address admin_,
                  bytes memory _data
              ) payable ERC1967Proxy(_logic, _data) {
                  assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                  _changeAdmin(admin_);
              }
              /**
               * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
               */
              modifier ifAdmin() {
                  if (msg.sender == _getAdmin()) {
                      _;
                  } else {
                      _fallback();
                  }
              }
              /**
               * @dev Returns the current admin.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
               *
               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
               * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
               */
              function admin() external ifAdmin returns (address admin_) {
                  admin_ = _getAdmin();
              }
              /**
               * @dev Returns the current implementation.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
               *
               * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
               * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
               * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
               */
              function implementation() external ifAdmin returns (address implementation_) {
                  implementation_ = _implementation();
              }
              /**
               * @dev Changes the admin of the proxy.
               *
               * Emits an {AdminChanged} event.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
               */
              function changeAdmin(address newAdmin) external virtual ifAdmin {
                  _changeAdmin(newAdmin);
              }
              /**
               * @dev Upgrade the implementation of the proxy.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
               */
              function upgradeTo(address newImplementation) external ifAdmin {
                  _upgradeToAndCall(newImplementation, bytes(""), false);
              }
              /**
               * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
               * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
               * proxied contract.
               *
               * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
               */
              function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                  _upgradeToAndCall(newImplementation, data, true);
              }
              /**
               * @dev Returns the current admin.
               */
              function _admin() internal view virtual returns (address) {
                  return _getAdmin();
              }
              /**
               * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
               */
              function _beforeFallback() internal virtual override {
                  require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                  super._beforeFallback();
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)
          pragma solidity ^0.8.0;
          import "../Proxy.sol";
          import "./ERC1967Upgrade.sol";
          /**
           * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
           * implementation address that can be changed. This address is stored in storage in the location specified by
           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
           * implementation behind the proxy.
           */
          contract ERC1967Proxy is Proxy, ERC1967Upgrade {
              /**
               * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
               *
               * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
               * function call, and allows initializating the storage of the proxy like a Solidity constructor.
               */
              constructor(address _logic, bytes memory _data) payable {
                  assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                  _upgradeToAndCall(_logic, _data, false);
              }
              /**
               * @dev Returns the current implementation address.
               */
              function _implementation() internal view virtual override returns (address impl) {
                  return ERC1967Upgrade._getImplementation();
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.0) (proxy/Proxy.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
           * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
           * be specified by overriding the virtual {_implementation} function.
           *
           * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
           * different contract through the {_delegate} function.
           *
           * The success and return data of the delegated call will be returned back to the caller of the proxy.
           */
          abstract contract Proxy {
              /**
               * @dev Delegates the current call to `implementation`.
               *
               * This function does not return to its internal call site, it will return directly to the external caller.
               */
              function _delegate(address implementation) internal virtual {
                  assembly {
                      // Copy msg.data. We take full control of memory in this inline assembly
                      // block because it will not return to Solidity code. We overwrite the
                      // Solidity scratch pad at memory position 0.
                      calldatacopy(0, 0, calldatasize())
                      // Call the implementation.
                      // out and outsize are 0 because we don't know the size yet.
                      let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                      // Copy the returned data.
                      returndatacopy(0, 0, returndatasize())
                      switch result
                      // delegatecall returns 0 on error.
                      case 0 {
                          revert(0, returndatasize())
                      }
                      default {
                          return(0, returndatasize())
                      }
                  }
              }
              /**
               * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
               * and {_fallback} should delegate.
               */
              function _implementation() internal view virtual returns (address);
              /**
               * @dev Delegates the current call to the address returned by `_implementation()`.
               *
               * This function does not return to its internall call site, it will return directly to the external caller.
               */
              function _fallback() internal virtual {
                  _beforeFallback();
                  _delegate(_implementation());
              }
              /**
               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
               * function in the contract matches the call data.
               */
              fallback() external payable virtual {
                  _fallback();
              }
              /**
               * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
               * is empty.
               */
              receive() external payable virtual {
                  _fallback();
              }
              /**
               * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
               * call, or as part of the Solidity `fallback` or `receive` functions.
               *
               * If overriden should call `super._beforeFallback()`.
               */
              function _beforeFallback() internal virtual {}
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
          pragma solidity ^0.8.2;
          import "../beacon/IBeacon.sol";
          import "../../interfaces/draft-IERC1822.sol";
          import "../../utils/Address.sol";
          import "../../utils/StorageSlot.sol";
          /**
           * @dev This abstract contract provides getters and event emitting update functions for
           * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
           *
           * _Available since v4.1._
           *
           * @custom:oz-upgrades-unsafe-allow delegatecall
           */
          abstract contract ERC1967Upgrade {
              // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
              bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
              /**
               * @dev Storage slot with the address of the current implementation.
               * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
               * validated in the constructor.
               */
              bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
              /**
               * @dev Emitted when the implementation is upgraded.
               */
              event Upgraded(address indexed implementation);
              /**
               * @dev Returns the current implementation address.
               */
              function _getImplementation() internal view returns (address) {
                  return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
              }
              /**
               * @dev Stores a new address in the EIP1967 implementation slot.
               */
              function _setImplementation(address newImplementation) private {
                  require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                  StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
              }
              /**
               * @dev Perform implementation upgrade
               *
               * Emits an {Upgraded} event.
               */
              function _upgradeTo(address newImplementation) internal {
                  _setImplementation(newImplementation);
                  emit Upgraded(newImplementation);
              }
              /**
               * @dev Perform implementation upgrade with additional setup call.
               *
               * Emits an {Upgraded} event.
               */
              function _upgradeToAndCall(
                  address newImplementation,
                  bytes memory data,
                  bool forceCall
              ) internal {
                  _upgradeTo(newImplementation);
                  if (data.length > 0 || forceCall) {
                      Address.functionDelegateCall(newImplementation, data);
                  }
              }
              /**
               * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
               *
               * Emits an {Upgraded} event.
               */
              function _upgradeToAndCallUUPS(
                  address newImplementation,
                  bytes memory data,
                  bool forceCall
              ) internal {
                  // Upgrades from old implementations will perform a rollback test. This test requires the new
                  // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                  // this special case will break upgrade paths from old UUPS implementation to new ones.
                  if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
                      _setImplementation(newImplementation);
                  } else {
                      try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                          require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                      } catch {
                          revert("ERC1967Upgrade: new implementation is not UUPS");
                      }
                      _upgradeToAndCall(newImplementation, data, forceCall);
                  }
              }
              /**
               * @dev Storage slot with the admin of the contract.
               * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
               * validated in the constructor.
               */
              bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
              /**
               * @dev Emitted when the admin account has changed.
               */
              event AdminChanged(address previousAdmin, address newAdmin);
              /**
               * @dev Returns the current admin.
               */
              function _getAdmin() internal view returns (address) {
                  return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
              }
              /**
               * @dev Stores a new address in the EIP1967 admin slot.
               */
              function _setAdmin(address newAdmin) private {
                  require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                  StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
              }
              /**
               * @dev Changes the admin of the proxy.
               *
               * Emits an {AdminChanged} event.
               */
              function _changeAdmin(address newAdmin) internal {
                  emit AdminChanged(_getAdmin(), newAdmin);
                  _setAdmin(newAdmin);
              }
              /**
               * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
               * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
               */
              bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
              /**
               * @dev Emitted when the beacon is upgraded.
               */
              event BeaconUpgraded(address indexed beacon);
              /**
               * @dev Returns the current beacon.
               */
              function _getBeacon() internal view returns (address) {
                  return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
              }
              /**
               * @dev Stores a new beacon in the EIP1967 beacon slot.
               */
              function _setBeacon(address newBeacon) private {
                  require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                  require(
                      Address.isContract(IBeacon(newBeacon).implementation()),
                      "ERC1967: beacon implementation is not a contract"
                  );
                  StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
              }
              /**
               * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
               * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
               *
               * Emits a {BeaconUpgraded} event.
               */
              function _upgradeBeaconToAndCall(
                  address newBeacon,
                  bytes memory data,
                  bool forceCall
              ) internal {
                  _setBeacon(newBeacon);
                  emit BeaconUpgraded(newBeacon);
                  if (data.length > 0 || forceCall) {
                      Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev This is the interface that {BeaconProxy} expects of its beacon.
           */
          interface IBeacon {
              /**
               * @dev Must return an address that can be used as a delegate call target.
               *
               * {BeaconProxy} will check that this address is a contract.
               */
              function implementation() external view returns (address);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
           * proxy whose upgrades are fully controlled by the current implementation.
           */
          interface IERC1822Proxiable {
              /**
               * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
               * address.
               *
               * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
               * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
               * function revert if invoked through a proxy.
               */
              function proxiableUUID() external view returns (bytes32);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.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
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Library for reading and writing primitive types to specific storage slots.
           *
           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
           * This library helps with reading and writing to such slots without the need for inline assembly.
           *
           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
           *
           * Example usage to set ERC1967 implementation slot:
           * ```
           * contract ERC1967 {
           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
           *
           *     function _getImplementation() internal view returns (address) {
           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
           *     }
           *
           *     function _setImplementation(address newImplementation) internal {
           *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
           *     }
           * }
           * ```
           *
           * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
           */
          library StorageSlot {
              struct AddressSlot {
                  address value;
              }
              struct BooleanSlot {
                  bool value;
              }
              struct Bytes32Slot {
                  bytes32 value;
              }
              struct Uint256Slot {
                  uint256 value;
              }
              /**
               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
               */
              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
               */
              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
               */
              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
               */
              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                  assembly {
                      r.slot := slot
                  }
              }
          }
          

          File 3 of 4: Outbox
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.4;
          import "./IBridge.sol";
          import "./IOutbox.sol";
          import "../libraries/MerkleLib.sol";
          import "../libraries/DelegateCallAware.sol";
          /// @dev this error is thrown since certain functions are only expected to be used in simulations, not in actual txs
          error SimulationOnlyEntrypoint();
          contract Outbox is DelegateCallAware, IOutbox {
              address public rollup; // the rollup contract
              IBridge public bridge; // the bridge contract
              mapping(uint256 => bytes32) public spent; // packed spent bitmap
              mapping(bytes32 => bytes32) public roots; // maps root hashes => L2 block hash
              struct L2ToL1Context {
                  uint128 l2Block;
                  uint128 l1Block;
                  uint128 timestamp;
                  bytes32 outputId;
                  address sender;
              }
              // Note, these variables are set and then wiped during a single transaction.
              // Therefore their values don't need to be maintained, and their slots will
              // be empty outside of transactions
              L2ToL1Context internal context;
              // default context values to be used in storage instead of zero, to save on storage refunds
              // it is assumed that arb-os never assigns these values to a valid leaf to be redeemed
              uint128 private constant L2BLOCK_DEFAULT_CONTEXT = type(uint128).max;
              uint128 private constant L1BLOCK_DEFAULT_CONTEXT = type(uint128).max;
              uint128 private constant TIMESTAMP_DEFAULT_CONTEXT = type(uint128).max;
              bytes32 private constant OUTPUTID_DEFAULT_CONTEXT = bytes32(type(uint256).max);
              address private constant SENDER_DEFAULT_CONTEXT = address(type(uint160).max);
              uint128 public constant OUTBOX_VERSION = 2;
              function initialize(IBridge _bridge) external onlyDelegated {
                  if (address(bridge) != address(0)) revert AlreadyInit();
                  // address zero is returned if no context is set, but the values used in storage
                  // are non-zero to save users some gas (as storage refunds are usually maxed out)
                  // EIP-1153 would help here
                  context = L2ToL1Context({
                      l2Block: L2BLOCK_DEFAULT_CONTEXT,
                      l1Block: L1BLOCK_DEFAULT_CONTEXT,
                      timestamp: TIMESTAMP_DEFAULT_CONTEXT,
                      outputId: OUTPUTID_DEFAULT_CONTEXT,
                      sender: SENDER_DEFAULT_CONTEXT
                  });
                  bridge = _bridge;
                  rollup = address(_bridge.rollup());
              }
              function updateSendRoot(bytes32 root, bytes32 l2BlockHash) external override {
                  if (msg.sender != rollup) revert NotRollup(msg.sender, rollup);
                  roots[root] = l2BlockHash;
                  emit SendRootUpdated(root, l2BlockHash);
              }
              /// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account
              /// When the return value is zero, that means this is a system message
              /// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
              function l2ToL1Sender() external view override returns (address) {
                  address sender = context.sender;
                  // we don't return the default context value to avoid a breaking change in the API
                  if (sender == SENDER_DEFAULT_CONTEXT) return address(0);
                  return sender;
              }
              /// @return l2Block return L2 block when the L2 tx was initiated or zero
              /// if no L2 to L1 transaction is active
              function l2ToL1Block() external view override returns (uint256) {
                  uint128 l2Block = context.l2Block;
                  // we don't return the default context value to avoid a breaking change in the API
                  if (l2Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0);
                  return uint256(l2Block);
              }
              /// @return l1Block return L1 block when the L2 tx was initiated or zero
              /// if no L2 to L1 transaction is active
              function l2ToL1EthBlock() external view override returns (uint256) {
                  uint128 l1Block = context.l1Block;
                  // we don't return the default context value to avoid a breaking change in the API
                  if (l1Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0);
                  return uint256(l1Block);
              }
              /// @return timestamp return L2 timestamp when the L2 tx was initiated or zero
              /// if no L2 to L1 transaction is active
              function l2ToL1Timestamp() external view override returns (uint256) {
                  uint128 timestamp = context.timestamp;
                  // we don't return the default context value to avoid a breaking change in the API
                  if (timestamp == TIMESTAMP_DEFAULT_CONTEXT) return uint256(0);
                  return uint256(timestamp);
              }
              /// @notice batch number is deprecated and now always returns 0
              function l2ToL1BatchNum() external pure override returns (uint256) {
                  return 0;
              }
              /// @return outputId returns the unique output identifier of the L2 to L1 tx or
              /// zero if no L2 to L1 transaction is active
              function l2ToL1OutputId() external view override returns (bytes32) {
                  bytes32 outputId = context.outputId;
                  // we don't return the default context value to avoid a breaking change in the API
                  if (outputId == OUTPUTID_DEFAULT_CONTEXT) return bytes32(0);
                  return outputId;
              }
              /**
               * @notice Executes a messages in an Outbox entry.
               * @dev Reverts if dispute period hasn't expired, since the outbox entry
               * is only created once the rollup confirms the respective assertion.
               * @param proof Merkle proof of message inclusion in send root
               * @param index Merkle path to message
               * @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
               * @param to destination address for L1 contract call
               * @param l2Block l2 block number at which sendTxToL1 call was made
               * @param l1Block l1 block number at which sendTxToL1 call was made
               * @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made
               * @param value wei in L1 message
               * @param data abi-encoded L1 message data
               */
              function executeTransaction(
                  bytes32[] calldata proof,
                  uint256 index,
                  address l2Sender,
                  address to,
                  uint256 l2Block,
                  uint256 l1Block,
                  uint256 l2Timestamp,
                  uint256 value,
                  bytes calldata data
              ) external {
                  bytes32 userTx = calculateItemHash(
                      l2Sender,
                      to,
                      l2Block,
                      l1Block,
                      l2Timestamp,
                      value,
                      data
                  );
                  recordOutputAsSpent(proof, index, userTx);
                  executeTransactionImpl(index, l2Sender, to, l2Block, l1Block, l2Timestamp, value, data);
              }
              /// @dev function used to simulate the result of a particular function call from the outbox
              /// it is useful for things such as gas estimates. This function includes all costs except for
              /// proof validation (which can be considered offchain as a somewhat of a fixed cost - it's
              /// not really a fixed cost, but can be treated as so with a fixed overhead for gas estimation).
              /// We can't include the cost of proof validation since this is intended to be used to simulate txs
              /// that are included in yet-to-be confirmed merkle roots. The simulation entrypoint could instead pretend
              /// to confirm a pending merkle root, but that would be less pratical for integrating with tooling.
              /// It is only possible to trigger it when the msg sender is address zero, which should be impossible
              /// unless under simulation in an eth_call or eth_estimateGas
              function executeTransactionSimulation(
                  uint256 index,
                  address l2Sender,
                  address to,
                  uint256 l2Block,
                  uint256 l1Block,
                  uint256 l2Timestamp,
                  uint256 value,
                  bytes calldata data
              ) external {
                  if (msg.sender != address(0)) revert SimulationOnlyEntrypoint();
                  executeTransactionImpl(index, l2Sender, to, l2Block, l1Block, l2Timestamp, value, data);
              }
              function executeTransactionImpl(
                  uint256 outputId,
                  address l2Sender,
                  address to,
                  uint256 l2Block,
                  uint256 l1Block,
                  uint256 l2Timestamp,
                  uint256 value,
                  bytes calldata data
              ) internal {
                  emit OutBoxTransactionExecuted(to, l2Sender, 0, outputId);
                  // we temporarily store the previous values so the outbox can naturally
                  // unwind itself when there are nested calls to `executeTransaction`
                  L2ToL1Context memory prevContext = context;
                  context = L2ToL1Context({
                      sender: l2Sender,
                      l2Block: uint128(l2Block),
                      l1Block: uint128(l1Block),
                      timestamp: uint128(l2Timestamp),
                      outputId: bytes32(outputId)
                  });
                  // set and reset vars around execution so they remain valid during call
                  executeBridgeCall(to, value, data);
                  context = prevContext;
              }
              function _calcSpentIndexOffset(uint256 index)
                  internal
                  view
                  returns (
                      uint256,
                      uint256,
                      bytes32
                  )
              {
                  uint256 spentIndex = index / 255; // Note: Reserves the MSB.
                  uint256 bitOffset = index % 255;
                  bytes32 replay = spent[spentIndex];
                  return (spentIndex, bitOffset, replay);
              }
              function _isSpent(uint256 bitOffset, bytes32 replay) internal pure returns (bool) {
                  return ((replay >> bitOffset) & bytes32(uint256(1))) != bytes32(0);
              }
              function isSpent(uint256 index) external view returns (bool) {
                  (, uint256 bitOffset, bytes32 replay) = _calcSpentIndexOffset(index);
                  return _isSpent(bitOffset, replay);
              }
              function recordOutputAsSpent(
                  bytes32[] memory proof,
                  uint256 index,
                  bytes32 item
              ) internal {
                  if (proof.length >= 256) revert ProofTooLong(proof.length);
                  if (index >= 2**proof.length) revert PathNotMinimal(index, 2**proof.length);
                  // Hash the leaf an extra time to prove it's a leaf
                  bytes32 calcRoot = calculateMerkleRoot(proof, index, item);
                  if (roots[calcRoot] == bytes32(0)) revert UnknownRoot(calcRoot);
                  (uint256 spentIndex, uint256 bitOffset, bytes32 replay) = _calcSpentIndexOffset(index);
                  if (_isSpent(bitOffset, replay)) revert AlreadySpent(index);
                  spent[spentIndex] = (replay | bytes32(1 << bitOffset));
              }
              function executeBridgeCall(
                  address to,
                  uint256 value,
                  bytes memory data
              ) internal {
                  (bool success, bytes memory returndata) = bridge.executeCall(to, value, data);
                  if (!success) {
                      if (returndata.length > 0) {
                          // solhint-disable-next-line no-inline-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert BridgeCallFailed();
                      }
                  }
              }
              function calculateItemHash(
                  address l2Sender,
                  address to,
                  uint256 l2Block,
                  uint256 l1Block,
                  uint256 l2Timestamp,
                  uint256 value,
                  bytes calldata data
              ) public pure returns (bytes32) {
                  return
                      keccak256(abi.encodePacked(l2Sender, to, l2Block, l1Block, l2Timestamp, value, data));
              }
              function calculateMerkleRoot(
                  bytes32[] memory proof,
                  uint256 path,
                  bytes32 item
              ) public pure returns (bytes32) {
                  return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item)));
              }
          }
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.4;
          import {NotContract, NotRollupOrOwner} from "../libraries/Error.sol";
          import "./IOwnable.sol";
          /// @dev Thrown when an un-authorized address tries to access an only-inbox function
          /// @param sender The un-authorized sender
          error NotDelayedInbox(address sender);
          /// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function
          /// @param sender The un-authorized sender
          error NotSequencerInbox(address sender);
          /// @dev Thrown when an un-authorized address tries to access an only-outbox function
          /// @param sender The un-authorized sender
          error NotOutbox(address sender);
          /// @dev the provided outbox address isn't valid
          /// @param outbox address of outbox being set
          error InvalidOutboxSet(address outbox);
          interface IBridge {
              event MessageDelivered(
                  uint256 indexed messageIndex,
                  bytes32 indexed beforeInboxAcc,
                  address inbox,
                  uint8 kind,
                  address sender,
                  bytes32 messageDataHash,
                  uint256 baseFeeL1,
                  uint64 timestamp
              );
              event BridgeCallTriggered(
                  address indexed outbox,
                  address indexed to,
                  uint256 value,
                  bytes data
              );
              event InboxToggle(address indexed inbox, bool enabled);
              event OutboxToggle(address indexed outbox, bool enabled);
              event SequencerInboxUpdated(address newSequencerInbox);
              function enqueueDelayedMessage(
                  uint8 kind,
                  address sender,
                  bytes32 messageDataHash
              ) external payable returns (uint256);
              function enqueueSequencerMessage(bytes32 dataHash, uint256 afterDelayedMessagesRead)
                  external
                  returns (
                      uint256 seqMessageIndex,
                      bytes32 beforeAcc,
                      bytes32 delayedAcc,
                      bytes32 acc
                  );
              function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
                  external
                  returns (uint256 msgNum);
              function executeCall(
                  address to,
                  uint256 value,
                  bytes calldata data
              ) external returns (bool success, bytes memory returnData);
              // These are only callable by the admin
              function setDelayedInbox(address inbox, bool enabled) external;
              function setOutbox(address inbox, bool enabled) external;
              function setSequencerInbox(address _sequencerInbox) external;
              // View functions
              function sequencerInbox() external view returns (address);
              function activeOutbox() external view returns (address);
              function allowedDelayedInboxes(address inbox) external view returns (bool);
              function allowedOutboxes(address outbox) external view returns (bool);
              function delayedInboxAccs(uint256 index) external view returns (bytes32);
              function sequencerInboxAccs(uint256 index) external view returns (bytes32);
              function delayedMessageCount() external view returns (uint256);
              function sequencerMessageCount() external view returns (uint256);
              function rollup() external view returns (IOwnable);
          }
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.4;
          import {AlreadyInit, NotRollup} from "../libraries/Error.sol";
          /// @dev The provided proof was too long
          /// @param proofLength The length of the too-long proof
          error ProofTooLong(uint256 proofLength);
          /// @dev The output index was greater than the maximum
          /// @param index The output index
          /// @param maxIndex The max the index could be
          error PathNotMinimal(uint256 index, uint256 maxIndex);
          /// @dev The calculated root does not exist
          /// @param root The calculated root
          error UnknownRoot(bytes32 root);
          /// @dev The record has already been spent
          /// @param index The index of the spent record
          error AlreadySpent(uint256 index);
          /// @dev A call to the bridge failed with no return data
          error BridgeCallFailed();
          interface IOutbox {
              event SendRootUpdated(bytes32 indexed blockHash, bytes32 indexed outputRoot);
              event OutBoxTransactionExecuted(
                  address indexed to,
                  address indexed l2Sender,
                  uint256 indexed zero,
                  uint256 transactionIndex
              );
              function l2ToL1Sender() external view returns (address);
              function l2ToL1Block() external view returns (uint256);
              function l2ToL1EthBlock() external view returns (uint256);
              function l2ToL1Timestamp() external view returns (uint256);
              // @deprecated batch number is now always 0
              function l2ToL1BatchNum() external view returns (uint256);
              function l2ToL1OutputId() external view returns (bytes32);
              function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external;
          }
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.4;
          import {MerkleProofTooLong} from "./Error.sol";
          library MerkleLib {
              function generateRoot(bytes32[] memory _hashes) internal pure returns (bytes32) {
                  bytes32[] memory prevLayer = _hashes;
                  while (prevLayer.length > 1) {
                      bytes32[] memory nextLayer = new bytes32[]((prevLayer.length + 1) / 2);
                      for (uint256 i = 0; i < nextLayer.length; i++) {
                          if (2 * i + 1 < prevLayer.length) {
                              nextLayer[i] = keccak256(
                                  abi.encodePacked(prevLayer[2 * i], prevLayer[2 * i + 1])
                              );
                          } else {
                              nextLayer[i] = prevLayer[2 * i];
                          }
                      }
                      prevLayer = nextLayer;
                  }
                  return prevLayer[0];
              }
              function calculateRoot(
                  bytes32[] memory nodes,
                  uint256 route,
                  bytes32 item
              ) internal pure returns (bytes32) {
                  uint256 proofItems = nodes.length;
                  if (proofItems > 256) revert MerkleProofTooLong(proofItems, 256);
                  bytes32 h = item;
                  for (uint256 i = 0; i < proofItems; i++) {
                      bytes32 node = nodes[i];
                      if (route % 2 == 0) {
                          assembly {
                              mstore(0x00, h)
                              mstore(0x20, node)
                              h := keccak256(0x00, 0x40)
                          }
                      } else {
                          assembly {
                              mstore(0x00, node)
                              mstore(0x20, h)
                              h := keccak256(0x00, 0x40)
                          }
                      }
                      route /= 2;
                  }
                  return h;
              }
          }
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.0;
          import {NotOwner} from "./Error.sol";
          /// @dev A stateless contract that allows you to infer if the current call has been delegated or not
          /// Pattern used here is from UUPS implementation by the OpenZeppelin team
          abstract contract DelegateCallAware {
              address private immutable __self = address(this);
              /**
               * @dev Check that the execution is being performed through a delegate call. This allows a function to be
               * callable on the proxy contract but not on the logic contract.
               */
              modifier onlyDelegated() {
                  require(address(this) != __self, "Function must be called through delegatecall");
                  _;
              }
              /**
               * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
               * callable on the implementing contract but not through proxies.
               */
              modifier notDelegated() {
                  require(address(this) == __self, "Function must not be called through delegatecall");
                  _;
              }
              /// @dev Check that msg.sender is the current EIP 1967 proxy admin
              modifier onlyProxyOwner() {
                  // Storage slot with the admin of the proxy contract
                  // This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1
                  bytes32 slot = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                  address admin;
                  assembly {
                      admin := sload(slot)
                  }
                  if (msg.sender != admin) revert NotOwner(msg.sender, admin);
                  _;
              }
          }
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.4;
          /// @dev Init was already called
          error AlreadyInit();
          /// Init was called with param set to zero that must be nonzero
          error HadZeroInit();
          /// @dev Thrown when non owner tries to access an only-owner function
          /// @param sender The msg.sender who is not the owner
          /// @param owner The owner address
          error NotOwner(address sender, address owner);
          /// @dev Thrown when an address that is not the rollup tries to call an only-rollup function
          /// @param sender The sender who is not the rollup
          /// @param rollup The rollup address authorized to call this function
          error NotRollup(address sender, address rollup);
          /// @dev Thrown when the contract was not called directly from the origin ie msg.sender != tx.origin
          error NotOrigin();
          /// @dev Provided data was too large
          /// @param dataLength The length of the data that is too large
          /// @param maxDataLength The max length the data can be
          error DataTooLarge(uint256 dataLength, uint256 maxDataLength);
          /// @dev The provided is not a contract and was expected to be
          /// @param addr The adddress in question
          error NotContract(address addr);
          /// @dev The merkle proof provided was too long
          /// @param actualLength The length of the merkle proof provided
          /// @param maxProofLength The max length a merkle proof can have
          error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength);
          /// @dev Thrown when an un-authorized address tries to access an admin function
          /// @param sender The un-authorized sender
          /// @param rollup The rollup, which would be authorized
          /// @param owner The rollup's owner, which would be authorized
          error NotRollupOrOwner(address sender, address rollup, address owner);
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.4;
          interface IOwnable {
              function owner() external view returns (address);
          }
          

          File 4 of 4: Bridge
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.4;
          import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
          import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
          import {
              NotContract,
              NotRollupOrOwner,
              NotDelayedInbox,
              NotSequencerInbox,
              NotOutbox,
              InvalidOutboxSet,
              BadSequencerMessageNumber
          } from "../libraries/Error.sol";
          import "./IBridge.sol";
          import "./Messages.sol";
          import "../libraries/DelegateCallAware.sol";
          import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol";
          /**
           * @title Staging ground for incoming and outgoing messages
           * @notice Holds the inbox accumulator for sequenced and delayed messages.
           * It is also the ETH escrow for value sent with these messages.
           * Since the escrow is held here, this contract also contains a list of allowed
           * outboxes that can make calls from here and withdraw this escrow.
           */
          contract Bridge is Initializable, DelegateCallAware, IBridge {
              using AddressUpgradeable for address;
              struct InOutInfo {
                  uint256 index;
                  bool allowed;
              }
              mapping(address => InOutInfo) private allowedDelayedInboxesMap;
              mapping(address => InOutInfo) private allowedOutboxesMap;
              address[] public allowedDelayedInboxList;
              address[] public allowedOutboxList;
              address private _activeOutbox;
              /// @inheritdoc IBridge
              bytes32[] public delayedInboxAccs;
              /// @inheritdoc IBridge
              bytes32[] public sequencerInboxAccs;
              IOwnable public rollup;
              address public sequencerInbox;
              uint256 public override sequencerReportedSubMessageCount;
              address private constant EMPTY_ACTIVEOUTBOX = address(type(uint160).max);
              function initialize(IOwnable rollup_) external initializer onlyDelegated {
                  _activeOutbox = EMPTY_ACTIVEOUTBOX;
                  rollup = rollup_;
              }
              modifier onlyRollupOrOwner() {
                  if (msg.sender != address(rollup)) {
                      address rollupOwner = rollup.owner();
                      if (msg.sender != rollupOwner) {
                          revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
                      }
                  }
                  _;
              }
              /// @dev returns the address of current active Outbox, or zero if no outbox is active
              function activeOutbox() public view returns (address) {
                  address outbox = _activeOutbox;
                  // address zero is returned if no outbox is set, but the value used in storage
                  // is non-zero to save users some gas (as storage refunds are usually maxed out)
                  // EIP-1153 would help here.
                  // we don't return `EMPTY_ACTIVEOUTBOX` to avoid a breaking change on the current api
                  if (outbox == EMPTY_ACTIVEOUTBOX) return address(0);
                  return outbox;
              }
              function allowedDelayedInboxes(address inbox) external view returns (bool) {
                  return allowedDelayedInboxesMap[inbox].allowed;
              }
              function allowedOutboxes(address outbox) external view returns (bool) {
                  return allowedOutboxesMap[outbox].allowed;
              }
              modifier onlySequencerInbox() {
                  if (msg.sender != sequencerInbox) revert NotSequencerInbox(msg.sender);
                  _;
              }
              function enqueueSequencerMessage(
                  bytes32 dataHash,
                  uint256 afterDelayedMessagesRead,
                  uint256 prevMessageCount,
                  uint256 newMessageCount
              )
                  external
                  onlySequencerInbox
                  returns (
                      uint256 seqMessageIndex,
                      bytes32 beforeAcc,
                      bytes32 delayedAcc,
                      bytes32 acc
                  )
              {
                  if (
                      sequencerReportedSubMessageCount != prevMessageCount &&
                      prevMessageCount != 0 &&
                      sequencerReportedSubMessageCount != 0
                  ) {
                      revert BadSequencerMessageNumber(sequencerReportedSubMessageCount, prevMessageCount);
                  }
                  sequencerReportedSubMessageCount = newMessageCount;
                  seqMessageIndex = sequencerInboxAccs.length;
                  if (sequencerInboxAccs.length > 0) {
                      beforeAcc = sequencerInboxAccs[sequencerInboxAccs.length - 1];
                  }
                  if (afterDelayedMessagesRead > 0) {
                      delayedAcc = delayedInboxAccs[afterDelayedMessagesRead - 1];
                  }
                  acc = keccak256(abi.encodePacked(beforeAcc, dataHash, delayedAcc));
                  sequencerInboxAccs.push(acc);
              }
              /// @inheritdoc IBridge
              function submitBatchSpendingReport(address sender, bytes32 messageDataHash)
                  external
                  onlySequencerInbox
                  returns (uint256)
              {
                  return
                      addMessageToDelayedAccumulator(
                          L1MessageType_batchPostingReport,
                          sender,
                          uint64(block.number),
                          uint64(block.timestamp), // solhint-disable-line not-rely-on-time,
                          block.basefee,
                          messageDataHash
                      );
              }
              /// @inheritdoc IBridge
              function enqueueDelayedMessage(
                  uint8 kind,
                  address sender,
                  bytes32 messageDataHash
              ) external payable returns (uint256) {
                  if (!allowedDelayedInboxesMap[msg.sender].allowed) revert NotDelayedInbox(msg.sender);
                  return
                      addMessageToDelayedAccumulator(
                          kind,
                          sender,
                          uint64(block.number),
                          uint64(block.timestamp), // solhint-disable-line not-rely-on-time
                          block.basefee,
                          messageDataHash
                      );
              }
              function addMessageToDelayedAccumulator(
                  uint8 kind,
                  address sender,
                  uint64 blockNumber,
                  uint64 blockTimestamp,
                  uint256 baseFeeL1,
                  bytes32 messageDataHash
              ) internal returns (uint256) {
                  uint256 count = delayedInboxAccs.length;
                  bytes32 messageHash = Messages.messageHash(
                      kind,
                      sender,
                      blockNumber,
                      blockTimestamp,
                      count,
                      baseFeeL1,
                      messageDataHash
                  );
                  bytes32 prevAcc = 0;
                  if (count > 0) {
                      prevAcc = delayedInboxAccs[count - 1];
                  }
                  delayedInboxAccs.push(Messages.accumulateInboxMessage(prevAcc, messageHash));
                  emit MessageDelivered(
                      count,
                      prevAcc,
                      msg.sender,
                      kind,
                      sender,
                      messageDataHash,
                      baseFeeL1,
                      blockTimestamp
                  );
                  return count;
              }
              function executeCall(
                  address to,
                  uint256 value,
                  bytes calldata data
              ) external returns (bool success, bytes memory returnData) {
                  if (!allowedOutboxesMap[msg.sender].allowed) revert NotOutbox(msg.sender);
                  if (data.length > 0 && !to.isContract()) revert NotContract(to);
                  address prevOutbox = _activeOutbox;
                  _activeOutbox = msg.sender;
                  // We set and reset active outbox around external call so activeOutbox remains valid during call
                  // We use a low level call here since we want to bubble up whether it succeeded or failed to the caller
                  // rather than reverting on failure as well as allow contract and non-contract calls
                  // solhint-disable-next-line avoid-low-level-calls
                  (success, returnData) = to.call{value: value}(data);
                  _activeOutbox = prevOutbox;
                  emit BridgeCallTriggered(msg.sender, to, value, data);
              }
              function setSequencerInbox(address _sequencerInbox) external onlyRollupOrOwner {
                  sequencerInbox = _sequencerInbox;
                  emit SequencerInboxUpdated(_sequencerInbox);
              }
              function setDelayedInbox(address inbox, bool enabled) external onlyRollupOrOwner {
                  InOutInfo storage info = allowedDelayedInboxesMap[inbox];
                  bool alreadyEnabled = info.allowed;
                  emit InboxToggle(inbox, enabled);
                  if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
                      return;
                  }
                  if (enabled) {
                      allowedDelayedInboxesMap[inbox] = InOutInfo(allowedDelayedInboxList.length, true);
                      allowedDelayedInboxList.push(inbox);
                  } else {
                      allowedDelayedInboxList[info.index] = allowedDelayedInboxList[
                          allowedDelayedInboxList.length - 1
                      ];
                      allowedDelayedInboxesMap[allowedDelayedInboxList[info.index]].index = info.index;
                      allowedDelayedInboxList.pop();
                      delete allowedDelayedInboxesMap[inbox];
                  }
              }
              function setOutbox(address outbox, bool enabled) external onlyRollupOrOwner {
                  if (outbox == EMPTY_ACTIVEOUTBOX) revert InvalidOutboxSet(outbox);
                  InOutInfo storage info = allowedOutboxesMap[outbox];
                  bool alreadyEnabled = info.allowed;
                  emit OutboxToggle(outbox, enabled);
                  if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
                      return;
                  }
                  if (enabled) {
                      allowedOutboxesMap[outbox] = InOutInfo(allowedOutboxList.length, true);
                      allowedOutboxList.push(outbox);
                  } else {
                      allowedOutboxList[info.index] = allowedOutboxList[allowedOutboxList.length - 1];
                      allowedOutboxesMap[allowedOutboxList[info.index]].index = info.index;
                      allowedOutboxList.pop();
                      delete allowedOutboxesMap[outbox];
                  }
              }
              function setSequencerReportedSubMessageCount(uint256 newMsgCount) external onlyRollupOrOwner {
                  sequencerReportedSubMessageCount = newMsgCount;
              }
              function delayedMessageCount() external view override returns (uint256) {
                  return delayedInboxAccs.length;
              }
              function sequencerMessageCount() external view returns (uint256) {
                  return sequencerInboxAccs.length;
              }
              /// @dev For the classic -> nitro migration. TODO: remove post-migration.
              function acceptFundsFromOldBridge() external payable {}
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)
          pragma solidity ^0.8.0;
          import "../../utils/AddressUpgradeable.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.
           *
           * 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 initialize the implementation contract, you can either invoke the
           * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
           *
           * [.hljs-theme-light.nopadding]
           * ```
           * /// @custom:oz-upgrades-unsafe-allow constructor
           * constructor() initializer {}
           * ```
           * ====
           */
          abstract contract Initializable {
              /**
               * @dev Indicates that the contract has been initialized.
               */
              bool private _initialized;
              /**
               * @dev Indicates that the contract is in the process of being initialized.
               */
              bool private _initializing;
              /**
               * @dev Modifier to protect an initializer function from being invoked twice.
               */
              modifier initializer() {
                  // If the contract is initializing we ignore whether _initialized is set in order to support multiple
                  // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
                  // contract may have been reentered.
                  require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");
                  bool isTopLevelCall = !_initializing;
                  if (isTopLevelCall) {
                      _initializing = true;
                      _initialized = true;
                  }
                  _;
                  if (isTopLevelCall) {
                      _initializing = false;
                  }
              }
              /**
               * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
               * {initializer} modifier, directly or indirectly.
               */
              modifier onlyInitializing() {
                  require(_initializing, "Initializable: contract is not initializing");
                  _;
              }
              function _isConstructor() private view returns (bool) {
                  return !AddressUpgradeable.isContract(address(this));
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
          pragma solidity ^0.8.1;
          /**
           * @dev Collection of functions related to the address type
           */
          library AddressUpgradeable {
              /**
               * @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 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
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.4;
          /// @dev Init was already called
          error AlreadyInit();
          /// Init was called with param set to zero that must be nonzero
          error HadZeroInit();
          /// @dev Thrown when non owner tries to access an only-owner function
          /// @param sender The msg.sender who is not the owner
          /// @param owner The owner address
          error NotOwner(address sender, address owner);
          /// @dev Thrown when an address that is not the rollup tries to call an only-rollup function
          /// @param sender The sender who is not the rollup
          /// @param rollup The rollup address authorized to call this function
          error NotRollup(address sender, address rollup);
          /// @dev Thrown when the contract was not called directly from the origin ie msg.sender != tx.origin
          error NotOrigin();
          /// @dev Provided data was too large
          /// @param dataLength The length of the data that is too large
          /// @param maxDataLength The max length the data can be
          error DataTooLarge(uint256 dataLength, uint256 maxDataLength);
          /// @dev The provided is not a contract and was expected to be
          /// @param addr The adddress in question
          error NotContract(address addr);
          /// @dev The merkle proof provided was too long
          /// @param actualLength The length of the merkle proof provided
          /// @param maxProofLength The max length a merkle proof can have
          error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength);
          /// @dev Thrown when an un-authorized address tries to access an admin function
          /// @param sender The un-authorized sender
          /// @param rollup The rollup, which would be authorized
          /// @param owner The rollup's owner, which would be authorized
          error NotRollupOrOwner(address sender, address rollup, address owner);
          // Bridge Errors
          /// @dev Thrown when an un-authorized address tries to access an only-inbox function
          /// @param sender The un-authorized sender
          error NotDelayedInbox(address sender);
          /// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function
          /// @param sender The un-authorized sender
          error NotSequencerInbox(address sender);
          /// @dev Thrown when an un-authorized address tries to access an only-outbox function
          /// @param sender The un-authorized sender
          error NotOutbox(address sender);
          /// @dev the provided outbox address isn't valid
          /// @param outbox address of outbox being set
          error InvalidOutboxSet(address outbox);
          // Inbox Errors
          /// @dev The contract is paused, so cannot be paused
          error AlreadyPaused();
          /// @dev The contract is unpaused, so cannot be unpaused
          error AlreadyUnpaused();
          /// @dev The contract is paused
          error Paused();
          /// @dev msg.value sent to the inbox isn't high enough
          error InsufficientValue(uint256 expected, uint256 actual);
          /// @dev submission cost provided isn't enough to create retryable ticket
          error InsufficientSubmissionCost(uint256 expected, uint256 actual);
          /// @dev address not allowed to interact with the given contract
          error NotAllowedOrigin(address origin);
          /// @dev used to convey retryable tx data in eth calls without requiring a tx trace
          /// this follows a pattern similar to EIP-3668 where reverts surface call information
          error RetryableData(
              address from,
              address to,
              uint256 l2CallValue,
              uint256 deposit,
              uint256 maxSubmissionCost,
              address excessFeeRefundAddress,
              address callValueRefundAddress,
              uint256 gasLimit,
              uint256 maxFeePerGas,
              bytes data
          );
          // Outbox Errors
          /// @dev The provided proof was too long
          /// @param proofLength The length of the too-long proof
          error ProofTooLong(uint256 proofLength);
          /// @dev The output index was greater than the maximum
          /// @param index The output index
          /// @param maxIndex The max the index could be
          error PathNotMinimal(uint256 index, uint256 maxIndex);
          /// @dev The calculated root does not exist
          /// @param root The calculated root
          error UnknownRoot(bytes32 root);
          /// @dev The record has already been spent
          /// @param index The index of the spent record
          error AlreadySpent(uint256 index);
          /// @dev A call to the bridge failed with no return data
          error BridgeCallFailed();
          // Sequencer Inbox Errors
          /// @dev Thrown when someone attempts to read fewer messages than have already been read
          error DelayedBackwards();
          /// @dev Thrown when someone attempts to read more messages than exist
          error DelayedTooFar();
          /// @dev Force include can only read messages more blocks old than the delay period
          error ForceIncludeBlockTooSoon();
          /// @dev Force include can only read messages more seconds old than the delay period
          error ForceIncludeTimeTooSoon();
          /// @dev The message provided did not match the hash in the delayed inbox
          error IncorrectMessagePreimage();
          /// @dev This can only be called by the batch poster
          error NotBatchPoster();
          /// @dev The sequence number provided to this message was inconsistent with the number of batches already included
          error BadSequencerNumber(uint256 stored, uint256 received);
          /// @dev The sequence message number provided to this message was inconsistent with the previous one
          error BadSequencerMessageNumber(uint256 stored, uint256 received);
          /// @dev The batch data has the inbox authenticated bit set, but the batch data was not authenticated by the inbox
          error DataNotAuthenticated();
          /// @dev Tried to create an already valid Data Availability Service keyset
          error AlreadyValidDASKeyset(bytes32);
          /// @dev Tried to use or invalidate an already invalid Data Availability Service keyset
          error NoSuchKeyset(bytes32);
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          // solhint-disable-next-line compiler-version
          pragma solidity >=0.6.9 <0.9.0;
          import "./IOwnable.sol";
          interface IBridge {
              event MessageDelivered(
                  uint256 indexed messageIndex,
                  bytes32 indexed beforeInboxAcc,
                  address inbox,
                  uint8 kind,
                  address sender,
                  bytes32 messageDataHash,
                  uint256 baseFeeL1,
                  uint64 timestamp
              );
              event BridgeCallTriggered(
                  address indexed outbox,
                  address indexed to,
                  uint256 value,
                  bytes data
              );
              event InboxToggle(address indexed inbox, bool enabled);
              event OutboxToggle(address indexed outbox, bool enabled);
              event SequencerInboxUpdated(address newSequencerInbox);
              function allowedDelayedInboxList(uint256) external returns (address);
              function allowedOutboxList(uint256) external returns (address);
              /// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
              function delayedInboxAccs(uint256) external view returns (bytes32);
              /// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
              function sequencerInboxAccs(uint256) external view returns (bytes32);
              function rollup() external view returns (IOwnable);
              function sequencerInbox() external view returns (address);
              function activeOutbox() external view returns (address);
              function allowedDelayedInboxes(address inbox) external view returns (bool);
              function allowedOutboxes(address outbox) external view returns (bool);
              function sequencerReportedSubMessageCount() external view returns (uint256);
              /**
               * @dev Enqueue a message in the delayed inbox accumulator.
               *      These messages are later sequenced in the SequencerInbox, either
               *      by the sequencer as part of a normal batch, or by force inclusion.
               */
              function enqueueDelayedMessage(
                  uint8 kind,
                  address sender,
                  bytes32 messageDataHash
              ) external payable returns (uint256);
              function executeCall(
                  address to,
                  uint256 value,
                  bytes calldata data
              ) external returns (bool success, bytes memory returnData);
              function delayedMessageCount() external view returns (uint256);
              function sequencerMessageCount() external view returns (uint256);
              // ---------- onlySequencerInbox functions ----------
              function enqueueSequencerMessage(
                  bytes32 dataHash,
                  uint256 afterDelayedMessagesRead,
                  uint256 prevMessageCount,
                  uint256 newMessageCount
              )
                  external
                  returns (
                      uint256 seqMessageIndex,
                      bytes32 beforeAcc,
                      bytes32 delayedAcc,
                      bytes32 acc
                  );
              /**
               * @dev Allows the sequencer inbox to submit a delayed message of the batchPostingReport type
               *      This is done through a separate function entrypoint instead of allowing the sequencer inbox
               *      to call `enqueueDelayedMessage` to avoid the gas overhead of an extra SLOAD in either
               *      every delayed inbox or every sequencer inbox call.
               */
              function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
                  external
                  returns (uint256 msgNum);
              // ---------- onlyRollupOrOwner functions ----------
              function setSequencerInbox(address _sequencerInbox) external;
              function setDelayedInbox(address inbox, bool enabled) external;
              function setOutbox(address inbox, bool enabled) external;
              // ---------- initializer ----------
              function initialize(IOwnable rollup_) external;
          }
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.0;
          library Messages {
              function messageHash(
                  uint8 kind,
                  address sender,
                  uint64 blockNumber,
                  uint64 timestamp,
                  uint256 inboxSeqNum,
                  uint256 baseFeeL1,
                  bytes32 messageDataHash
              ) internal pure returns (bytes32) {
                  return
                      keccak256(
                          abi.encodePacked(
                              kind,
                              sender,
                              blockNumber,
                              timestamp,
                              inboxSeqNum,
                              baseFeeL1,
                              messageDataHash
                          )
                      );
              }
              function accumulateInboxMessage(bytes32 prevAcc, bytes32 message)
                  internal
                  pure
                  returns (bytes32)
              {
                  return keccak256(abi.encodePacked(prevAcc, message));
              }
          }
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.0;
          import {NotOwner} from "./Error.sol";
          /// @dev A stateless contract that allows you to infer if the current call has been delegated or not
          /// Pattern used here is from UUPS implementation by the OpenZeppelin team
          abstract contract DelegateCallAware {
              address private immutable __self = address(this);
              /**
               * @dev Check that the execution is being performed through a delegate call. This allows a function to be
               * callable on the proxy contract but not on the logic contract.
               */
              modifier onlyDelegated() {
                  require(address(this) != __self, "Function must be called through delegatecall");
                  _;
              }
              /**
               * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
               * callable on the implementing contract but not through proxies.
               */
              modifier notDelegated() {
                  require(address(this) == __self, "Function must not be called through delegatecall");
                  _;
              }
              /// @dev Check that msg.sender is the current EIP 1967 proxy admin
              modifier onlyProxyOwner() {
                  // Storage slot with the admin of the proxy contract
                  // This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1
                  bytes32 slot = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                  address admin;
                  assembly {
                      admin := sload(slot)
                  }
                  if (msg.sender != admin) revert NotOwner(msg.sender, admin);
                  _;
              }
          }
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          pragma solidity ^0.8.4;
          uint8 constant L2_MSG = 3;
          uint8 constant L1MessageType_L2FundedByL1 = 7;
          uint8 constant L1MessageType_submitRetryableTx = 9;
          uint8 constant L1MessageType_ethDeposit = 12;
          uint8 constant L1MessageType_batchPostingReport = 13;
          uint8 constant L2MessageType_unsignedEOATx = 0;
          uint8 constant L2MessageType_unsignedContractTx = 1;
          uint8 constant ROLLUP_PROTOCOL_EVENT_TYPE = 8;
          uint8 constant INITIALIZATION_MSG_TYPE = 11;
          // Copyright 2021-2022, Offchain Labs, Inc.
          // For license information, see https://github.com/nitro/blob/master/LICENSE
          // SPDX-License-Identifier: BUSL-1.1
          // solhint-disable-next-line compiler-version
          pragma solidity >=0.4.21 <0.9.0;
          interface IOwnable {
              function owner() external view returns (address);
          }