ETH Price: $2,571.02 (+2.37%)

Transaction Decoder

Block:
22854029 at Jul-05-2025 03:52:11 PM +UTC
Transaction Fee:
0.00017707349952633 ETH $0.46
Gas Used:
164,334 Gas / 1.077521995 Gwei

Emitted Events:

173 ERC1967Proxy.0x85f32beeaff2d0019a8d196f06790c9a652191759c46643311344fd38920423c( 0x85f32beeaff2d0019a8d196f06790c9a652191759c46643311344fd38920423c, 0x00000000000000000000000041f2f55571f9e8e3ba511adc48879bd67626a2b6, 000000000000000000000000000000000000000000000006c6b935b8bbd40000 )
174 ERC1967Proxy.0x9eb7fc80523943f28950bbb71ed6d584effe3e1e02ca4ddc8c86e5ee1558c096( 0x9eb7fc80523943f28950bbb71ed6d584effe3e1e02ca4ddc8c86e5ee1558c096, 00000000000000000000000000000000000000000000000000000000000000c0, e31a0075c679720f616a8cc6d1180be163db9642fa63e122df060f7ad370840e, 00000000000000000000000041f2f55571f9e8e3ba511adc48879bd67626a2b6, 000000000000000000000000000000000000000000000000000000000012fee5, 0000000000000000000000000000000000000000000000000000000068694a2b, 0000000000000000000000000000000000000000000000000000000000000420, 44ca766eeffb18cadfbd8023b668de9b4ec07702c3f5ece494d9bf4ed043e4b8, 0000000000000000000000000000000000000000000000000000000000000260, 0000000000000000000000000000000000000000000000000000000000000320, 0000000000000000000000000000000000000000000000000000000000000032, 00000000000000000000000041f2f55571f9e8e3ba511adc48879bd67626a2b6, 00000000000000000000000000000000000000000000000000000000015cb98d, 00000000000000000000000000000000000000000000000000000000015cb98d, 0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000000000000000000b7ca, 000000000000000000000000000000000000000000000000000000000e4e1c00, 000000000000000000000000000000000000000000000000000000000012fee5, 0000000000000000000000000000000000000000000000000000000068694a2b, 00000000000000000000000000000000000000000000000000000000015cb98c, 3de0f60c9a35f1a9974da649ef13f41ab3fa3b707a6ce036ce9160cc3bda9dea, 0000000000000000000000000000000000000000000000000000000000000008, 0000000000000000000000000000000000000000000000000000000000000032, 00000000000000000000000000000000000000000000000000000000004c4b40, 0000000000000000000000000000000000000000000000000000000050298966, 0000000000000000000000000000000000000000000000000000000023c34600, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000226, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000001, 01d3a4664901afc17af5702c4af8a77598be4b8b46b7164d9901b00bd5fc5ef5, 0000000000000000000000000000000000000000000000000000000000000000 )
175 ERC1967Proxy.0x7156d026e6a3864d290a971910746f96477d3901e33c4b2375e4ee00dabe7d87( 0x7156d026e6a3864d290a971910746f96477d3901e33c4b2375e4ee00dabe7d87, 000000000000000000000000000000000000000000000000000000000012fee6, 000000000000000000000000000000000000000000000000000000000012fdcc, 0000000000000000000000000000000000000000000000000000000000000000, 00000000000000000000000000000000000000000000000000000000015cb98d, 000000000000000000000000000000000000000000000000000000006650cf33 )

Account State Difference:

  Address   Before After State Difference Code
0x06a9Ab27...755Feb19a
(Taiko: Inbox)
0x41F2F555...67626A2b6
4.574089985270883832 Eth
Nonce: 212542
4.57391291177122643 Eth
Nonce: 212543
0.000177073499657402
(BuilderNet)
29.3411014837721762 Eth29.3412000841721762 Eth0.0000986004

Execution Trace

ERC1967Proxy.47faad14( )
  • TaikoWrapper.proposeBatch( _params=0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002C0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000041F2F55571F9E8E3BA511ADC48879BD67626A2B600000000000000000000000041F2F55571F9E8E3BA511ADC48879BD67626A2B6CAA8C8292BF1316CB6C201557882DBF707F27624B41230D0E7AC03FAEE9311D6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001E000000000000000000000000000000000000000000000000000000000000000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B7CA00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000, _txList=0x )
    • ERC1967Proxy.STATICCALL( )
      • ForcedInclusionStore.DELEGATECALL( )
      • ERC1967Proxy.47faad14( )
        • PacayaForkRouter.47faad14( )
          • MainnetInbox.proposeBatch( _params=0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000041F2F55571F9E8E3BA511ADC48879BD67626A2B600000000000000000000000041F2F55571F9E8E3BA511ADC48879BD67626A2B6CAA8C8292BF1316CB6C201557882DBF707F27624B41230D0E7AC03FAEE9311D6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001E000000000000000000000000000000000000000000000000000000000000000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B7CA00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000, _txList=0x )
            File 1 of 7: ERC1967Proxy
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.7.0) (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 initializing the storage of the proxy like a Solidity constructor.
                 */
                constructor(address _logic, bytes memory _data) payable {
                    _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.6.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 overridden 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 internal 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 overridden should call `super._beforeFallback()`.
                 */
                function _beforeFallback() internal virtual {}
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
            pragma solidity ^0.8.2;
            import "../beacon/IBeacon.sol";
            import "../../interfaces/IERC1967.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._
             */
            abstract contract ERC1967Upgrade is IERC1967 {
                // 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 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 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 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.9.0) (interfaces/IERC1967.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
             *
             * _Available since v4.8.3._
             */
            interface IERC1967 {
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            }
            // 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.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            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:
             * ```solidity
             * 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`, `uint256`._
             * _Available since v4.9 for `string`, `bytes`._
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes value;
                }
                /**
                 * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                 */
                function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                 */
                function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                 */
                function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                 */
                function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            

            File 2 of 7: ERC1967Proxy
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.7.0) (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 initializing the storage of the proxy like a Solidity constructor.
                 */
                constructor(address _logic, bytes memory _data) payable {
                    _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.6.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 overridden 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 internal 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 overridden should call `super._beforeFallback()`.
                 */
                function _beforeFallback() internal virtual {}
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
            pragma solidity ^0.8.2;
            import "../beacon/IBeacon.sol";
            import "../../interfaces/IERC1967.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._
             */
            abstract contract ERC1967Upgrade is IERC1967 {
                // 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 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 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 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.9.0) (interfaces/IERC1967.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
             *
             * _Available since v4.8.3._
             */
            interface IERC1967 {
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            }
            // 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.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            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:
             * ```solidity
             * 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`, `uint256`._
             * _Available since v4.9 for `string`, `bytes`._
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes value;
                }
                /**
                 * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                 */
                function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                 */
                function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                 */
                function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                 */
                function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            

            File 3 of 7: TaikoWrapper
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
            import "src/layer1/based/IProposeBatch.sol";
            import "./ForcedInclusionStore.sol";
            /// @title TaikoWrapper
            /// @dev This contract is part of a delayed inbox implementation to enforce the inclusion of
            /// transactions.
            /// The current design is a simplified and can be improved with the following ideas:
            /// 1. Fee-Based Request Prioritization:
            ///    - Proposers can selectively fulfill pending requests based on transaction fees.
            ///    - Requests not yet due can be processed earlier if fees are attractive, incentivizing timely
            /// execution.
            ///
            /// 2. Rate Limit Control:
            ///    - A rate-limiting mechanism ensures a minimum interval of 12*N seconds between request
            /// fulfillments.
            ///    - Prevents proposers from being overwhelmed during high request volume, ensuring system
            /// stability.
            ///
            /// 3. Calldata and Blob Support:
            ///    - Supports both calldata and blobs in the transaction list.
            ///
            /// 4. Gas-Efficient Request Storage:
            ///    - Avoids storing full request data in contract storage.
            ///    - Saves only the request hash and its timestamp.
            ///    - Leverages Ethereum events to store request details off-chain.
            ///    - Proposers can reconstruct requests as needed, minimizing on-chain storage and gas
            /// consumption.
            ///
            /// @custom:security-contact [email protected]
            contract TaikoWrapper is EssentialContract, IProposeBatch {
                using LibMath for uint256;
                /// @dev Event emitted when a forced inclusion is processed.
                event ForcedInclusionProcessed(IForcedInclusionStore.ForcedInclusion);
                error InvalidBlockTxs();
                error InvalidBlobHashesSize();
                error InvalidBlobHash();
                error InvalidBlobByteOffset();
                error InvalidBlobByteSize();
                error InvalidBlobCreatedIn();
                error InvalidBlockSize();
                error InvalidTimeShift();
                error InvalidSignalSlots();
                error OldestForcedInclusionDue();
                uint16 public constant MIN_TXS_PER_FORCED_INCLUSION = 512;
                IProposeBatch public immutable inbox;
                IForcedInclusionStore public immutable forcedInclusionStore;
                address public immutable preconfRouter;
                uint256[50] private __gap;
                constructor(
                    address _inbox,
                    address _forcedInclusionStore,
                    address _preconfRouter
                )
                    nonZeroAddr(_inbox)
                    nonZeroAddr(_forcedInclusionStore)
                    EssentialContract(address(0))
                {
                    inbox = IProposeBatch(_inbox);
                    forcedInclusionStore = IForcedInclusionStore(_forcedInclusionStore);
                    preconfRouter = _preconfRouter;
                }
                function init(address _owner) external initializer {
                    __Essential_init(_owner);
                }
                /// @inheritdoc IProposeBatch
                function proposeBatch(
                    bytes calldata _params,
                    bytes calldata _txList
                )
                    external
                    onlyFromOptional(preconfRouter)
                    nonReentrant
                    returns (ITaikoInbox.BatchInfo memory, ITaikoInbox.BatchMetadata memory)
                {
                    (bytes memory bytesX, bytes memory bytesY) = abi.decode(_params, (bytes, bytes));
                    if (bytesX.length == 0) {
                        require(!forcedInclusionStore.isOldestForcedInclusionDue(), OldestForcedInclusionDue());
                    } else {
                        _validateForcedInclusionParams(forcedInclusionStore, bytesX);
                        inbox.proposeBatch(bytesX, "");
                    }
                    // Propose the normal batch after the potential forced inclusion batch.
                    ITaikoInbox.BatchParams memory params = abi.decode(bytesY, (ITaikoInbox.BatchParams));
                    require(params.blobParams.blobHashes.length == 0, ITaikoInbox.InvalidBlobParams());
                    require(params.blobParams.createdIn == 0, ITaikoInbox.InvalidBlobCreatedIn());
                    return inbox.proposeBatch(bytesY, _txList);
                }
                function _validateForcedInclusionParams(
                    IForcedInclusionStore _forcedInclusionStore,
                    bytes memory _bytesX
                )
                    internal
                {
                    ITaikoInbox.BatchParams memory p = abi.decode(_bytesX, (ITaikoInbox.BatchParams));
                    IForcedInclusionStore.ForcedInclusion memory inclusion =
                        _forcedInclusionStore.consumeOldestForcedInclusion(p.proposer);
                    // Only one block can be built from the request
                    require(p.blocks.length == 1, InvalidBlockSize());
                    // Need to make sure enough transactions in the forced inclusion request are included.
                    require(p.blocks[0].numTransactions >= MIN_TXS_PER_FORCED_INCLUSION, InvalidBlockTxs());
                    require(p.blocks[0].timeShift == 0, InvalidTimeShift());
                    require(p.blocks[0].signalSlots.length == 0, InvalidSignalSlots());
                    require(p.blobParams.blobHashes.length == 1, InvalidBlobHashesSize());
                    require(p.blobParams.blobHashes[0] == inclusion.blobHash, InvalidBlobHash());
                    require(p.blobParams.byteOffset == inclusion.blobByteOffset, InvalidBlobByteOffset());
                    require(p.blobParams.byteSize == inclusion.blobByteSize, InvalidBlobByteSize());
                    require(p.blobParams.createdIn == inclusion.blobCreatedIn, InvalidBlobCreatedIn());
                    emit ForcedInclusionProcessed(inclusion);
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Interface of the ERC20 standard as defined in the EIP.
             */
            interface IERC20 {
                /**
                 * @dev Emitted when `value` tokens are moved from one account (`from`) to
                 * another (`to`).
                 *
                 * Note that `value` may be zero.
                 */
                event Transfer(address indexed from, address indexed to, uint256 value);
                /**
                 * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                 * a call to {approve}. `value` is the new allowance.
                 */
                event Approval(address indexed owner, address indexed spender, uint256 value);
                /**
                 * @dev Returns the amount of tokens in existence.
                 */
                function totalSupply() external view returns (uint256);
                /**
                 * @dev Returns the amount of tokens owned by `account`.
                 */
                function balanceOf(address account) external view returns (uint256);
                /**
                 * @dev Moves `amount` tokens from the caller's account to `to`.
                 *
                 * Returns a boolean value indicating whether the operation succeeded.
                 *
                 * Emits a {Transfer} event.
                 */
                function transfer(address to, uint256 amount) external returns (bool);
                /**
                 * @dev Returns the remaining number of tokens that `spender` will be
                 * allowed to spend on behalf of `owner` through {transferFrom}. This is
                 * zero by default.
                 *
                 * This value changes when {approve} or {transferFrom} are called.
                 */
                function allowance(address owner, address spender) external view returns (uint256);
                /**
                 * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                 *
                 * Returns a boolean value indicating whether the operation succeeded.
                 *
                 * IMPORTANT: Beware that changing an allowance with this method brings the risk
                 * that someone may use both the old and the new allowance by unfortunate
                 * transaction ordering. One possible solution to mitigate this race
                 * condition is to first reduce the spender's allowance to 0 and set the
                 * desired value afterwards:
                 * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                 *
                 * Emits an {Approval} event.
                 */
                function approve(address spender, uint256 amount) external returns (bool);
                /**
                 * @dev Moves `amount` tokens from `from` to `to` using the
                 * allowance mechanism. `amount` is then deducted from the caller's
                 * allowance.
                 *
                 * Returns a boolean value indicating whether the operation succeeded.
                 *
                 * Emits a {Transfer} event.
                 */
                function transferFrom(address from, address to, uint256 amount) external returns (bool);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "./ITaikoInbox.sol";
            /// @title IProposeBatch
            /// @notice This interface defines the proposeBatch function that is also part of the ITaikoInbox
            /// interface.
            /// @custom:security-contact [email protected]
            interface IProposeBatch {
                /// @notice Proposes a batch of blocks.
                /// @param _params ABI-encoded parameters.
                /// @param _txList The transaction list in calldata. If the txList is empty, blob will be used
                /// for data availability.
                /// @return info_ The info of the proposed batch.
                /// @return meta_ The mmetadata of the proposed batch.
                function proposeBatch(
                    bytes calldata _params,
                    bytes calldata _txList
                )
                    external
                    returns (ITaikoInbox.BatchInfo memory info_, ITaikoInbox.BatchMetadata memory meta_);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "src/shared/common/EssentialContract.sol";
            import "src/shared/libs/LibMath.sol";
            import "src/shared/libs/LibAddress.sol";
            import "src/shared/libs/LibStrings.sol";
            import "src/layer1/based/ITaikoInbox.sol";
            import "./IForcedInclusionStore.sol";
            /// @title ForcedInclusionStore
            /// @dev A contract for storing and managing forced inclusion requests. Forced inclusions allow
            /// users to pay a fee to ensure their transactions are included in a block. The contract maintains
            /// a FIFO queue of inclusion requests.
            /// @custom:security-contact
            contract ForcedInclusionStore is EssentialContract, IForcedInclusionStore {
                using LibAddress for address;
                using LibMath for uint256;
                uint8 public immutable inclusionDelay; // measured in the number of batches
                uint64 public immutable feeInGwei;
                ITaikoInbox public immutable inbox;
                address public immutable inboxWrapper;
                mapping(uint256 id => ForcedInclusion inclusion) public queue; // slot 1
                uint64 public head; // slot 2
                uint64 public tail;
                uint64 public lastProcessedAtBatchId;
                uint64 private __reserved1;
                uint256[48] private __gap;
                // keccak256(abi.encode(uint256(keccak256("taiko.alethia.forcedinclusion.storage.TransactionGuard"))
                // - 1) & ~bytes32(uint256(0xff));
                bytes32 private constant _TRANSACTION_GUARD =
                    0x5a1e3a5f720a5155ea49503410bd539c2a6a2a71c3684875803b191fd01b8100;
                modifier onlyStandaloneTx() {
                    bytes32 guard;
                    assembly {
                        guard := tload(_TRANSACTION_GUARD)
                    }
                    require(guard == 0, MultipleCallsInOneTx());
                    assembly {
                        tstore(_TRANSACTION_GUARD, 1)
                    }
                    _;
                    // Will clean up at the end of the transaction
                }
                constructor(
                    uint8 _inclusionDelay,
                    uint64 _feeInGwei,
                    address _inbox,
                    address _inboxWrapper
                )
                    nonZeroValue(_inclusionDelay)
                    nonZeroValue(_feeInGwei)
                    nonZeroAddr(_inbox)
                    nonZeroAddr(_inboxWrapper)
                    EssentialContract(address(0))
                {
                    inclusionDelay = _inclusionDelay;
                    feeInGwei = _feeInGwei;
                    inbox = ITaikoInbox(_inbox);
                    inboxWrapper = _inboxWrapper;
                }
                function init(address _owner) external initializer {
                    __Essential_init(_owner);
                }
                function storeForcedInclusion(
                    uint8 blobIndex,
                    uint32 blobByteOffset,
                    uint32 blobByteSize
                )
                    external
                    payable
                    onlyStandaloneTx
                    whenNotPaused
                {
                    bytes32 blobHash = _blobHash(blobIndex);
                    require(blobHash != bytes32(0), BlobNotFound());
                    require(msg.value == feeInGwei * 1 gwei, IncorrectFee());
                    ForcedInclusion memory inclusion = ForcedInclusion({
                        blobHash: blobHash,
                        feeInGwei: uint64(msg.value / 1 gwei),
                        createdAtBatchId: _nextBatchId(),
                        blobByteOffset: blobByteOffset,
                        blobByteSize: blobByteSize,
                        blobCreatedIn: uint64(block.number)
                    });
                    queue[tail++] = inclusion;
                    emit ForcedInclusionStored(inclusion);
                }
                function consumeOldestForcedInclusion(address _feeRecipient)
                    external
                    onlyFrom(inboxWrapper)
                    nonReentrant
                    returns (ForcedInclusion memory inclusion_)
                {
                    // we only need to check the first one, since it will be the oldest.
                    ForcedInclusion storage inclusion = queue[head];
                    require(inclusion.createdAtBatchId != 0, NoForcedInclusionFound());
                    inclusion_ = inclusion;
                    lastProcessedAtBatchId = _nextBatchId();
                    unchecked {
                        delete queue[head++];
                        _feeRecipient.sendEtherAndVerify(inclusion_.feeInGwei * 1 gwei);
                    }
                    emit ForcedInclusionConsumed(inclusion_);
                }
                function getForcedInclusion(uint256 index) external view returns (ForcedInclusion memory) {
                    require(index >= head, InvalidIndex());
                    require(index < tail, InvalidIndex());
                    return queue[index];
                }
                function getOldestForcedInclusionDeadline() public view returns (uint256) {
                    if (head == tail) return type(uint256).max;
                    ForcedInclusion storage inclusion = queue[head];
                    if (inclusion.createdAtBatchId == 0) return type(uint256).max;
                    unchecked {
                        return uint256(lastProcessedAtBatchId).max(inclusion.createdAtBatchId) + inclusionDelay;
                    }
                }
                function isOldestForcedInclusionDue() external view returns (bool) {
                    uint256 deadline = getOldestForcedInclusionDeadline();
                    return deadline != type(uint256).max && _nextBatchId() >= deadline;
                }
                // @dev Override this function for easier testing blobs
                function _blobHash(uint8 blobIndex) internal view virtual returns (bytes32) {
                    return blobhash(blobIndex);
                }
                function _nextBatchId() private view returns (uint64) {
                    return inbox.getStats2().numBatches;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "src/shared/based/LibSharedData.sol";
            /// @title TaikoInbox
            /// @notice Acts as the inbox for the Taiko Alethia protocol, a simplified version of the
            /// original Taiko-Based Contestable Rollup (BCR). The tier-based proof system and
            /// contestation mechanisms have been removed.
            ///
            /// Key assumptions of this protocol:
            /// - Block proposals and proofs are asynchronous. Proofs are not available at proposal time,
            ///   unlike Taiko Gwyneth, which assumes synchronous composability.
            /// - Proofs are presumed error-free and thoroughly validated, with proof type management
            ///   delegated to IVerifier contracts.
            ///
            /// @dev Registered in the address resolver as "taiko".
            /// @custom:security-contact [email protected]
            interface ITaikoInbox {
                struct BlockParams {
                    // the max number of transactions in this block. Note that if there are not enough
                    // transactions in calldata or blobs, the block will contains as many transactions as
                    // possible.
                    uint16 numTransactions;
                    // The time difference (in seconds) between the timestamp of this block and
                    // the timestamp of the parent block in the same batch. For the first block in a batch,
                    // there is not parent block in the same batch, so the time shift should be 0.
                    uint8 timeShift;
                    // Signals sent on L1 and need to sync to this L2 block.
                    bytes32[] signalSlots;
                }
                struct BlobParams {
                    // The hashes of the blob. Note that if this array is not empty.  `firstBlobIndex` and
                    // `numBlobs` must be 0.
                    bytes32[] blobHashes;
                    // The index of the first blob in this batch.
                    uint8 firstBlobIndex;
                    // The number of blobs in this batch. Blobs are initially concatenated and subsequently
                    // decompressed via Zlib.
                    uint8 numBlobs;
                    // The byte offset of the blob in the batch.
                    uint32 byteOffset;
                    // The byte size of the blob.
                    uint32 byteSize;
                    // The block number when the blob was created. This value is only non-zero when
                    // `blobHashes` are non-empty.
                    uint64 createdIn;
                }
                struct BatchParams {
                    address proposer;
                    address coinbase;
                    bytes32 parentMetaHash;
                    uint64 anchorBlockId;
                    uint64 lastBlockTimestamp;
                    bool revertIfNotFirstProposal;
                    // Specifies the number of blocks to be generated from this batch.
                    BlobParams blobParams;
                    BlockParams[] blocks;
                }
                /// @dev This struct holds batch information essential for constructing blocks offchain, but it
                /// does not include data necessary for batch proving.
                struct BatchInfo {
                    bytes32 txsHash;
                    // Data to build L2 blocks
                    BlockParams[] blocks;
                    bytes32[] blobHashes;
                    bytes32 extraData;
                    address coinbase;
                    uint64 proposedIn; // Used by node/client
                    uint64 blobCreatedIn;
                    uint32 blobByteOffset;
                    uint32 blobByteSize;
                    uint32 gasLimit;
                    uint64 lastBlockId;
                    uint64 lastBlockTimestamp;
                    // Data for the L2 anchor transaction, shared by all blocks in the batch
                    uint64 anchorBlockId;
                    // corresponds to the `_anchorStateRoot` parameter in the anchor transaction.
                    // The batch's validity proof shall verify the integrity of these two values.
                    bytes32 anchorBlockHash;
                    LibSharedData.BaseFeeConfig baseFeeConfig;
                }
                /// @dev This struct holds batch metadata essential for proving the batch.
                struct BatchMetadata {
                    bytes32 infoHash;
                    address proposer;
                    uint64 batchId;
                    uint64 proposedAt; // Used by node/client
                }
                /// @notice Struct representing transition to be proven.
                struct Transition {
                    bytes32 parentHash;
                    bytes32 blockHash;
                    bytes32 stateRoot;
                }
                //  @notice Struct representing transition storage
                /// @notice 4 slots used.
                struct TransitionState {
                    bytes32 parentHash;
                    bytes32 blockHash;
                    bytes32 stateRoot;
                    address prover;
                    bool inProvingWindow;
                    uint48 createdAt;
                }
                /// @notice 3 slots used.
                struct Batch {
                    bytes32 metaHash; // slot 1
                    uint64 lastBlockId; // slot 2
                    uint96 reserved3;
                    uint96 livenessBond;
                    uint64 batchId; // slot 3
                    uint64 lastBlockTimestamp;
                    uint64 anchorBlockId;
                    uint24 nextTransitionId;
                    uint8 reserved4;
                    // The ID of the transaction that is used to verify this batch. However, if this batch is
                    // not verified as the last one in a transaction, verifiedTransitionId will remain zero.
                    uint24 verifiedTransitionId;
                }
                /// @notice Forge is only able to run coverage in case the contracts by default capable of
                /// compiling without any optimization (neither optimizer runs, no compiling --via-ir flag).
                struct Stats1 {
                    uint64 genesisHeight;
                    uint64 __reserved2;
                    uint64 lastSyncedBatchId;
                    uint64 lastSyncedAt;
                }
                struct Stats2 {
                    uint64 numBatches;
                    uint64 lastVerifiedBatchId;
                    bool paused;
                    uint56 lastProposedIn;
                    uint64 lastUnpausedAt;
                }
                struct ForkHeights {
                    uint64 ontake; // measured with block number.
                    uint64 pacaya; // measured with the batch Id, not block number.
                    uint64 shasta; // measured with the batch Id, not block number.
                    uint64 unzen; // measured with the batch Id, not block number.
                }
                /// @notice Struct holding Taiko configuration parameters. See {TaikoConfig}.
                struct Config {
                    /// @notice The chain ID of the network where Taiko contracts are deployed.
                    uint64 chainId;
                    /// @notice The maximum number of unverified batches the protocol supports.
                    uint64 maxUnverifiedBatches;
                    /// @notice Size of the batch ring buffer, allowing extra space for proposals.
                    uint64 batchRingBufferSize;
                    /// @notice The maximum number of verifications allowed when a batch is proposed or proved.
                    uint64 maxBatchesToVerify;
                    /// @notice The maximum gas limit allowed for a block.
                    uint32 blockMaxGasLimit;
                    /// @notice The amount of Taiko token as a prover liveness bond per batch.
                    uint96 livenessBondBase;
                    /// @notice The amount of Taiko token as a prover liveness bond per block. This field is
                    /// deprecated and its value will be ignored.
                    uint96 livenessBondPerBlock;
                    /// @notice The number of batches between two L2-to-L1 state root sync.
                    uint8 stateRootSyncInternal;
                    /// @notice The max differences of the anchor height and the current block number.
                    uint64 maxAnchorHeightOffset;
                    /// @notice Base fee configuration
                    LibSharedData.BaseFeeConfig baseFeeConfig;
                    /// @notice The proving window in seconds.
                    uint16 provingWindow;
                    /// @notice The time required for a transition to be used for verifying a batch.
                    uint24 cooldownWindow;
                    /// @notice The maximum number of signals to be received by TaikoL2.
                    uint8 maxSignalsToReceive;
                    /// @notice The maximum number of blocks per batch.
                    uint16 maxBlocksPerBatch;
                    /// @notice Historical heights of the forks.
                    ForkHeights forkHeights;
                }
                /// @notice Struct holding the state variables for the {Taiko} contract.
                struct State {
                    // Ring buffer for proposed batches and a some recent verified batches.
                    mapping(uint256 batchId_mod_batchRingBufferSize => Batch batch) batches;
                    // Indexing to transition ids (ring buffer not possible)
                    mapping(uint256 batchId => mapping(bytes32 parentHash => uint24 transitionId)) transitionIds;
                    // Ring buffer for transitions
                    mapping(
                        uint256 batchId_mod_batchRingBufferSize
                            => mapping(uint24 transitionId => TransitionState ts)
                    ) transitions;
                    bytes32 __reserve1; // slot 4 - was used as a ring buffer for Ether deposits
                    Stats1 stats1; // slot 5
                    Stats2 stats2; // slot 6
                    mapping(address account => uint256 bond) bondBalance;
                    uint256[43] __gap;
                }
                /// @notice Emitted when tokens are deposited into a user's bond balance.
                /// @param user The address of the user who deposited the tokens.
                /// @param amount The amount of tokens deposited.
                event BondDeposited(address indexed user, uint256 amount);
                /// @notice Emitted when tokens are withdrawn from a user's bond balance.
                /// @param user The address of the user who withdrew the tokens.
                /// @param amount The amount of tokens withdrawn.
                event BondWithdrawn(address indexed user, uint256 amount);
                /// @notice Emitted when a token is credited back to a user's bond balance.
                /// @param user The address of the user whose bond balance is credited.
                /// @param amount The amount of tokens credited.
                event BondCredited(address indexed user, uint256 amount);
                /// @notice Emitted when a token is debited from a user's bond balance.
                /// @param user The address of the user whose bond balance is debited.
                /// @param amount The amount of tokens debited.
                event BondDebited(address indexed user, uint256 amount);
                /// @notice Emitted when a batch is synced.
                /// @param stats1 The Stats1 data structure.
                event Stats1Updated(Stats1 stats1);
                /// @notice Emitted when some state variable values changed.
                /// @param stats2 The Stats2 data structure.
                event Stats2Updated(Stats2 stats2);
                /// @notice Emitted when a batch is proposed.
                /// @param info The info of the proposed batch.
                /// @param meta The metadata of the proposed batch.
                /// @param txList The tx list in calldata.
                event BatchProposed(BatchInfo info, BatchMetadata meta, bytes txList);
                /// @notice Emitted when multiple transitions are proved.
                /// @param verifier The address of the verifier.
                /// @param transitions The transitions data.
                event BatchesProved(address verifier, uint64[] batchIds, Transition[] transitions);
                /// @notice Emitted when a transition is overwritten by a conflicting one with the same parent
                /// hash but different block hash or state root.
                /// @param batchId The batch ID.
                /// @param oldTran The old transition overwritten.
                /// @param newTran The new transition.
                event ConflictingProof(uint64 batchId, TransitionState oldTran, Transition newTran);
                /// @notice Emitted when a batch is verified.
                /// @param batchId The ID of the verified batch.
                /// @param blockHash The hash of the verified batch.
                event BatchesVerified(uint64 batchId, bytes32 blockHash);
                error AnchorBlockIdSmallerThanParent();
                error AnchorBlockIdTooLarge();
                error AnchorBlockIdTooSmall();
                error ArraySizesMismatch();
                error BatchNotFound();
                error BatchVerified();
                error BeyondCurrentFork();
                error BlobNotFound();
                error BlockNotFound();
                error BlobNotSpecified();
                error ContractPaused();
                error CustomProposerMissing();
                error CustomProposerNotAllowed();
                error EtherNotPaidAsBond();
                error FirstBlockTimeShiftNotZero();
                error ForkNotActivated();
                error InsufficientBond();
                error InvalidBlobCreatedIn();
                error InvalidBlobParams();
                error InvalidGenesisBlockHash();
                error InvalidParams();
                error InvalidTransitionBlockHash();
                error InvalidTransitionParentHash();
                error InvalidTransitionStateRoot();
                error MetaHashMismatch();
                error MsgValueNotZero();
                error NoBlocksToProve();
                error NotFirstProposal();
                error NotInboxWrapper();
                error ParentMetaHashMismatch();
                error SameTransition();
                error SignalNotSent();
                error TimestampSmallerThanParent();
                error TimestampTooLarge();
                error TimestampTooSmall();
                error TooManyBatches();
                error TooManyBlocks();
                error TooManySignals();
                error TransitionNotFound();
                error ZeroAnchorBlockHash();
                /// @notice Proposes a batch of blocks.
                /// @param _params ABI-encoded parameters.
                /// @param _txList The transaction list in calldata. If the txList is empty, blob will be used
                /// for data availability.
                /// @return info_ The info of the proposed batch.
                /// @return meta_ The metadata of the proposed batch.
                function proposeBatch(
                    bytes calldata _params,
                    bytes calldata _txList
                )
                    external
                    returns (ITaikoInbox.BatchInfo memory info_, ITaikoInbox.BatchMetadata memory meta_);
                /// @notice Proves state transitions for multiple batches with a single aggregated proof.
                /// @param _params ABI-encoded parameter containing:
                /// - metas: Array of metadata for each batch being proved.
                /// - transitions: Array of batch transitions to be proved.
                /// @param _proof The aggregated cryptographic proof proving the batches transitions.
                function proveBatches(bytes calldata _params, bytes calldata _proof) external;
                /// @notice Deposits TAIKO tokens into the contract to be used as liveness bond.
                /// @param _amount The amount of TAIKO tokens to deposit.
                function depositBond(uint256 _amount) external payable;
                /// @notice Withdraws a specified amount of TAIKO tokens from the contract.
                /// @param _amount The amount of TAIKO tokens to withdraw.
                function withdrawBond(uint256 _amount) external;
                /// @notice Returns the TAIKO token balance of a specific user.
                /// @param _user The address of the user.
                /// @return The TAIKO token balance of the user.
                function bondBalanceOf(address _user) external view returns (uint256);
                /// @notice Retrieves the Bond token address. If Ether is used as bond, this function returns
                /// address(0).
                /// @return The Bond token address.
                function bondToken() external view returns (address);
                /// @notice Retrieves the first set of protocol statistics.
                /// @return Stats1 structure containing the statistics.
                function getStats1() external view returns (Stats1 memory);
                /// @notice Retrieves the second set of protocol statistics.
                /// @return Stats2 structure containing the statistics.
                function getStats2() external view returns (Stats2 memory);
                /// @notice Retrieves data about a specific batch.
                /// @param _batchId The ID of the batch to retrieve.
                /// @return batch_ The batch data.
                function getBatch(uint64 _batchId) external view returns (Batch memory batch_);
                /// @notice Retrieves a specific transition by batch ID and transition ID. This function may
                /// revert if the transition is not found.
                /// @param _batchId The batch ID.
                /// @param _tid The transition ID.
                /// @return The specified transition state.
                function getTransitionById(
                    uint64 _batchId,
                    uint24 _tid
                )
                    external
                    view
                    returns (ITaikoInbox.TransitionState memory);
                /// @notice Retrieves a specific transition by batch ID and parent Hash. This function may
                /// revert if the transition is not found.
                /// @param _batchId The batch ID.
                /// @param _parentHash The parent hash.
                /// @return The specified transition state.
                function getTransitionByParentHash(
                    uint64 _batchId,
                    bytes32 _parentHash
                )
                    external
                    view
                    returns (ITaikoInbox.TransitionState memory);
                /// @notice Retrieves the transition used for the last verified batch.
                /// @return batchId_ The batch ID of the last verified transition.
                /// @return blockId_ The block ID of the last verified block.
                /// @return ts_ The last verified transition.
                function getLastVerifiedTransition()
                    external
                    view
                    returns (uint64 batchId_, uint64 blockId_, TransitionState memory ts_);
                /// @notice Retrieves the transition used for the last synced batch.
                /// @return batchId_ The batch ID of the last synced transition.
                /// @return blockId_ The block ID of the last synced block.
                /// @return ts_ The last synced transition.
                function getLastSyncedTransition()
                    external
                    view
                    returns (uint64 batchId_, uint64 blockId_, TransitionState memory ts_);
                /// @notice Retrieves the transition used for verifying a batch.
                /// @param _batchId The batch ID.
                /// @return The transition used for verifying the batch.
                function getBatchVerifyingTransition(uint64 _batchId)
                    external
                    view
                    returns (TransitionState memory);
                /// @notice Retrieves the current protocol configuration.
                /// @return The current configuration.
                function pacayaConfig() external view returns (Config memory);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
            import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
            import "./IResolver.sol";
            /// @title EssentialContract
            /// @custom:security-contact [email protected]
            abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable {
                uint8 internal constant _FALSE = 1;
                uint8 internal constant _TRUE = 2;
                address private immutable __resolver;
                uint256[50] private __gapFromOldAddressResolver;
                /// @dev Slot 1.
                uint8 internal __reentry;
                uint8 internal __paused;
                uint256[49] private __gap;
                /// @notice Emitted when the contract is paused.
                /// @param account The account that paused the contract.
                event Paused(address account);
                /// @notice Emitted when the contract is unpaused.
                /// @param account The account that unpaused the contract.
                event Unpaused(address account);
                error INVALID_PAUSE_STATUS();
                error FUNC_NOT_IMPLEMENTED();
                error REENTRANT_CALL();
                error ACCESS_DENIED();
                error RESOLVER_NOT_FOUND();
                error ZERO_ADDRESS();
                error ZERO_VALUE();
                /// @dev Modifier that ensures the caller is the owner or resolved address of a given name.
                /// @param _name The name to check against.
                modifier onlyFromOwnerOrNamed(bytes32 _name) {
                    require(msg.sender == owner() || msg.sender == resolve(_name, true), ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is either the owner or a specified address.
                /// @param _addr The address to check against.
                modifier onlyFromOwnerOr(address _addr) {
                    require(msg.sender == owner() || msg.sender == _addr, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that reverts the function call, indicating it is not implemented.
                modifier notImplemented() {
                    revert FUNC_NOT_IMPLEMENTED();
                    _;
                }
                /// @dev Modifier that prevents reentrant calls to a function.
                modifier nonReentrant() {
                    require(_loadReentryLock() != _TRUE, REENTRANT_CALL());
                    _storeReentryLock(_TRUE);
                    _;
                    _storeReentryLock(_FALSE);
                }
                /// @dev Modifier that allows function execution only when the contract is paused.
                modifier whenPaused() {
                    require(paused(), INVALID_PAUSE_STATUS());
                    _;
                }
                /// @dev Modifier that allows function execution only when the contract is not paused.
                modifier whenNotPaused() {
                    require(!paused(), INVALID_PAUSE_STATUS());
                    _;
                }
                /// @dev Modifier that ensures the provided address is not the zero address.
                /// @param _addr The address to check.
                modifier nonZeroAddr(address _addr) {
                    require(_addr != address(0), ZERO_ADDRESS());
                    _;
                }
                /// @dev Modifier that ensures the provided value is not zero.
                /// @param _value The value to check.
                modifier nonZeroValue(uint256 _value) {
                    require(_value != 0, ZERO_VALUE());
                    _;
                }
                /// @dev Modifier that ensures the provided bytes32 value is not zero.
                /// @param _value The bytes32 value to check.
                modifier nonZeroBytes32(bytes32 _value) {
                    require(_value != 0, ZERO_VALUE());
                    _;
                }
                /// @dev Modifier that ensures the caller is the resolved address of a given
                /// name.
                /// @param _name The name to check against.
                modifier onlyFromNamed(bytes32 _name) {
                    require(msg.sender == resolve(_name, true), ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is the resolved address of a given
                /// name, if the name is set.
                /// @param _name The name to check against.
                modifier onlyFromOptionalNamed(bytes32 _name) {
                    address addr = resolve(_name, true);
                    require(addr == address(0) || msg.sender == addr, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is a resolved address to either _name1 or _name2
                /// name.
                /// @param _name1 The first name to check against.
                /// @param _name2 The second name to check against.
                modifier onlyFromNamedEither(bytes32 _name1, bytes32 _name2) {
                    require(
                        msg.sender == resolve(_name1, true) || msg.sender == resolve(_name2, true),
                        ACCESS_DENIED()
                    );
                    _;
                }
                /// @dev Modifier that ensures the caller is either of the two specified addresses.
                /// @param _addr1 The first address to check against.
                /// @param _addr2 The second address to check against.
                modifier onlyFromEither(address _addr1, address _addr2) {
                    require(msg.sender == _addr1 || msg.sender == _addr2, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is the specified address.
                /// @param _addr The address to check against.
                modifier onlyFrom(address _addr) {
                    require(msg.sender == _addr, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is the specified address.
                /// @param _addr The address to check against.
                modifier onlyFromOptional(address _addr) {
                    require(_addr == address(0) || msg.sender == _addr, ACCESS_DENIED());
                    _;
                }
                constructor(address _resolver) {
                    __resolver = _resolver;
                    _disableInitializers();
                }
                /// @notice Pauses the contract.
                function pause() public whenNotPaused {
                    _pause();
                    emit Paused(msg.sender);
                    // We call the authorize function here to avoid:
                    // Warning (5740): Unreachable code.
                    _authorizePause(msg.sender, true);
                }
                /// @notice Unpauses the contract.
                function unpause() public whenPaused {
                    _unpause();
                    emit Unpaused(msg.sender);
                    // We call the authorize function here to avoid:
                    // Warning (5740): Unreachable code.
                    _authorizePause(msg.sender, false);
                }
                function impl() public view returns (address) {
                    return _getImplementation();
                }
                /// @notice Returns true if the contract is paused, and false otherwise.
                /// @return true if paused, false otherwise.
                function paused() public view virtual returns (bool) {
                    return __paused == _TRUE;
                }
                function inNonReentrant() public view returns (bool) {
                    return _loadReentryLock() == _TRUE;
                }
                /// @notice Returns the address of this contract.
                /// @return The address of this contract.
                function resolver() public view virtual returns (address) {
                    return __resolver;
                }
                /// @notice Resolves a name to an address on a specific chain
                /// @param _chainId The chain ID to resolve the name on
                /// @param _name The name to resolve
                /// @param _allowZeroAddress Whether to allow resolving to the zero address
                /// @return The resolved address
                function resolve(
                    uint64 _chainId,
                    bytes32 _name,
                    bool _allowZeroAddress
                )
                    internal
                    view
                    returns (address)
                {
                    return IResolver(resolver()).resolve(_chainId, _name, _allowZeroAddress);
                }
                /// @notice Resolves a name to an address on the current chain
                /// @param _name The name to resolve
                /// @param _allowZeroAddress Whether to allow resolving to the zero address
                /// @return The resolved address
                function resolve(bytes32 _name, bool _allowZeroAddress) internal view returns (address) {
                    return IResolver(resolver()).resolve(block.chainid, _name, _allowZeroAddress);
                }
                /// @notice Initializes the contract.
                /// @param _owner The owner of this contract. msg.sender will be used if this value is zero.
                function __Essential_init(address _owner) internal virtual onlyInitializing {
                    __Context_init();
                    _transferOwnership(_owner == address(0) ? msg.sender : _owner);
                    __paused = _FALSE;
                }
                function _pause() internal virtual {
                    __paused = _TRUE;
                }
                function _unpause() internal virtual {
                    __paused = _FALSE;
                }
                function _authorizeUpgrade(address) internal virtual override onlyOwner { }
                function _authorizePause(address, bool) internal virtual onlyOwner { }
                // Stores the reentry lock
                function _storeReentryLock(uint8 _reentry) internal virtual {
                    __reentry = _reentry;
                }
                // Loads the reentry lock
                function _loadReentryLock() internal view virtual returns (uint8 reentry_) {
                    reentry_ = __reentry;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title LibMath
            /// @dev This library offers additional math functions for uint256.
            /// @custom:security-contact [email protected]
            library LibMath {
                /// @dev Returns the smaller of the two given values.
                /// @param _a The first number to compare.
                /// @param _b The second number to compare.
                /// @return The smaller of the two numbers.
                function min(uint256 _a, uint256 _b) internal pure returns (uint256) {
                    return _a > _b ? _b : _a;
                }
                /// @dev Returns the larger of the two given values.
                /// @param _a The first number to compare.
                /// @param _b The second number to compare.
                /// @return The larger of the two numbers.
                function max(uint256 _a, uint256 _b) internal pure returns (uint256) {
                    return _a > _b ? _a : _b;
                }
                function capToUint64(uint256 _value) internal pure returns (uint64) {
                    return uint64(min(_value, type(uint64).max));
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
            /// @title LibAddress
            /// @dev Provides utilities for address-related operations.
            /// @custom:security-contact [email protected]
            library LibAddress {
                error ETH_TRANSFER_FAILED();
                /// @dev Sends Ether to the specified address. This method will not revert even if sending ether
                /// fails.
                /// This function is inspired by
                /// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol
                /// @param _to The recipient address.
                /// @param _amount The amount of Ether to send in wei.
                /// @param _gasLimit The max amount gas to pay for this transaction.
                /// @return success_ true if the call is successful, false otherwise.
                function sendEther(
                    address _to,
                    uint256 _amount,
                    uint256 _gasLimit,
                    bytes memory _calldata
                )
                    internal
                    returns (bool success_)
                {
                    // Check for zero-address transactions
                    require(_to != address(0), ETH_TRANSFER_FAILED());
                    // dispatch message to recipient
                    // by assembly calling "handle" function
                    // we call via assembly to avoid memcopying a very large returndata
                    // returned by a malicious contract
                    assembly {
                        success_ :=
                            call(
                                _gasLimit, // gas
                                _to, // recipient
                                _amount, // ether value
                                add(_calldata, 0x20), // inloc
                                mload(_calldata), // inlen
                                0, // outloc
                                0 // outlen
                            )
                    }
                }
                /// @dev Sends Ether to the specified address. This method will revert if sending ether fails.
                /// @param _to The recipient address.
                /// @param _amount The amount of Ether to send in wei.
                /// @param _gasLimit The max amount gas to pay for this transaction.
                function sendEtherAndVerify(address _to, uint256 _amount, uint256 _gasLimit) internal {
                    if (_amount == 0) return;
                    require(sendEther(_to, _amount, _gasLimit, ""), ETH_TRANSFER_FAILED());
                }
                /// @dev Sends Ether to the specified address. This method will revert if sending ether fails.
                /// @param _to The recipient address.
                /// @param _amount The amount of Ether to send in wei.
                function sendEtherAndVerify(address _to, uint256 _amount) internal {
                    sendEtherAndVerify(_to, _amount, gasleft());
                }
                function supportsInterface(
                    address _addr,
                    bytes4 _interfaceId
                )
                    internal
                    view
                    returns (bool result_)
                {
                    (bool success, bytes memory data) =
                        _addr.staticcall(abi.encodeCall(IERC165.supportsInterface, (_interfaceId)));
                    if (success && data.length == 32) {
                        result_ = abi.decode(data, (bool));
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title LibStrings
            /// @custom:security-contact [email protected]
            library LibStrings {
                bytes32 internal constant B_AUTOMATA_DCAP_ATTESTATION = bytes32("automata_dcap_attestation");
                bytes32 internal constant B_SGX_GETH_AUTOMATA = bytes32("sgx_geth_automata");
                bytes32 internal constant B_BOND_TOKEN = bytes32("bond_token");
                bytes32 internal constant B_BRIDGE = bytes32("bridge");
                bytes32 internal constant B_BRIDGE_WATCHDOG = bytes32("bridge_watchdog");
                bytes32 internal constant B_BRIDGED_ERC1155 = bytes32("bridged_erc1155");
                bytes32 internal constant B_BRIDGED_ERC20 = bytes32("bridged_erc20");
                bytes32 internal constant B_BRIDGED_ERC721 = bytes32("bridged_erc721");
                bytes32 internal constant B_CHAIN_WATCHDOG = bytes32("chain_watchdog");
                bytes32 internal constant B_ERC1155_VAULT = bytes32("erc1155_vault");
                bytes32 internal constant B_ERC20_VAULT = bytes32("erc20_vault");
                bytes32 internal constant B_ERC721_VAULT = bytes32("erc721_vault");
                bytes32 internal constant B_FORCED_INCLUSION_STORE = bytes32("forced_inclusion_store");
                bytes32 internal constant B_PRECONF_WHITELIST = bytes32("preconf_whitelist");
                bytes32 internal constant B_PRECONF_WHITELIST_OWNER = bytes32("preconf_whitelist_owner");
                bytes32 internal constant B_PRECONF_ROUTER = bytes32("preconf_router");
                bytes32 internal constant B_TAIKO_WRAPPER = bytes32("taiko_wrapper");
                bytes32 internal constant B_PROOF_VERIFIER = bytes32("proof_verifier");
                bytes32 internal constant B_SGX_RETH_VERIFIER = bytes32("sgx_reth_verifier");
                bytes32 internal constant B_SGX_GETH_VERIFIER = bytes32("sgx_geth_verifier");
                bytes32 internal constant B_RISC0_RETH_VERIFIER = bytes32("risc0_reth_verifier");
                bytes32 internal constant B_SP1_RETH_VERIFIER = bytes32("sp1_reth_verifier");
                bytes32 internal constant B_PROVER_SET = bytes32("prover_set");
                bytes32 internal constant B_QUOTA_MANAGER = bytes32("quota_manager");
                bytes32 internal constant B_SIGNAL_SERVICE = bytes32("signal_service");
                bytes32 internal constant B_TAIKO = bytes32("taiko");
                bytes32 internal constant B_TAIKO_TOKEN = bytes32("taiko_token");
                bytes32 internal constant B_WITHDRAWER = bytes32("withdrawer");
                bytes32 internal constant H_SIGNAL_ROOT = keccak256("SIGNAL_ROOT");
                bytes32 internal constant H_STATE_ROOT = keccak256("STATE_ROOT");
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title IForcedInclusionStore
            /// @custom:security-contact [email protected]
            interface IForcedInclusionStore {
                struct ForcedInclusion {
                    bytes32 blobHash;
                    uint64 feeInGwei;
                    uint64 createdAtBatchId;
                    uint32 blobByteOffset;
                    uint32 blobByteSize;
                    uint64 blobCreatedIn;
                }
                /// @dev Event emitted when a forced inclusion is stored.
                event ForcedInclusionStored(ForcedInclusion forcedInclusion);
                /// @dev Event emitted when a forced inclusion is consumed.
                event ForcedInclusionConsumed(ForcedInclusion forcedInclusion);
                /// @dev Error thrown when a blob is not found.
                error BlobNotFound();
                /// @dev Error thrown when the parameters are invalid.
                error InvalidParams();
                /// @dev Error thrown when the fee is incorrect.
                error IncorrectFee();
                /// @dev Error thrown when the index is invalid.
                error InvalidIndex();
                /// @dev Error thrown when a forced inclusion is not found.
                error NoForcedInclusionFound();
                /// @dev Error thrown when a function is called more than once in one transaction.
                error MultipleCallsInOneTx();
                /// @dev Retrieve a forced inclusion request by its index.
                /// @param index The index of the forced inclusion request in the queue.
                /// @return The forced inclusion request at the specified index.
                function getForcedInclusion(uint256 index) external view returns (ForcedInclusion memory);
                /// @dev Get the deadline for the oldest forced inclusion.
                /// @return The deadline for the oldest forced inclusion.
                function getOldestForcedInclusionDeadline() external view returns (uint256);
                /// @dev Check if the oldest forced inclusion is due.
                /// @return True if the oldest forced inclusion is due, false otherwise.
                function isOldestForcedInclusionDue() external view returns (bool);
                /// @dev Consume a forced inclusion request.
                /// The inclusion request must be marked as processed and the priority fee must be paid to the
                /// caller.
                /// @param _feeRecipient The address to receive the priority fee.
                /// @return inclusion_ The forced inclusion request.
                function consumeOldestForcedInclusion(address _feeRecipient)
                    external
                    returns (ForcedInclusion memory);
                /// @dev Store a forced inclusion request.
                /// The priority fee must be paid to the contract.
                /// @param blobIndex The index of the blob that contains the transaction data.
                /// @param blobByteOffset The byte offset in the blob
                /// @param blobByteSize The size of the blob in bytes
                function storeForcedInclusion(
                    uint8 blobIndex,
                    uint32 blobByteOffset,
                    uint32 blobByteSize
                )
                    external
                    payable;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            library LibSharedData {
                /// @dev Struct that represents L2 basefee configurations
                struct BaseFeeConfig {
                    uint8 adjustmentQuotient;
                    uint8 sharingPctg;
                    uint32 gasIssuancePerSecond;
                    uint64 minGasExcess;
                    uint32 maxGasIssuancePerBlock;
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
            pragma solidity ^0.8.0;
            import "../../interfaces/draft-IERC1822.sol";
            import "../ERC1967/ERC1967Upgrade.sol";
            /**
             * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
             * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
             *
             * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
             * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
             * `UUPSUpgradeable` with a custom implementation of upgrades.
             *
             * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
             *
             * _Available since v4.1._
             */
            abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
                /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
                address private immutable __self = address(this);
                /**
                 * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
                 * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
                 * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
                 * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
                 * fail.
                 */
                modifier onlyProxy() {
                    require(address(this) != __self, "Function must be called through delegatecall");
                    require(_getImplementation() == __self, "Function must be called through active proxy");
                    _;
                }
                /**
                 * @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, "UUPSUpgradeable: must not be called through delegatecall");
                    _;
                }
                /**
                 * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
                 * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                 *
                 * 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. This is guaranteed by the `notDelegated` modifier.
                 */
                function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
                    return _IMPLEMENTATION_SLOT;
                }
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeTo(address newImplementation) public virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
                }
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                 * encoded in `data`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, data, true);
                }
                /**
                 * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                 * {upgradeTo} and {upgradeToAndCall}.
                 *
                 * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                 *
                 * ```solidity
                 * function _authorizeUpgrade(address) internal override onlyOwner {}
                 * ```
                 */
                function _authorizeUpgrade(address newImplementation) internal virtual;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
            pragma solidity ^0.8.0;
            import "./OwnableUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which provides access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership} and {acceptOwnership}.
             *
             * This module is used through inheritance. It will make available all functions
             * from parent (Ownable).
             */
            abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
                address private _pendingOwner;
                event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
                function __Ownable2Step_init() internal onlyInitializing {
                    __Ownable_init_unchained();
                }
                function __Ownable2Step_init_unchained() internal onlyInitializing {
                }
                /**
                 * @dev Returns the address of the pending owner.
                 */
                function pendingOwner() public view virtual returns (address) {
                    return _pendingOwner;
                }
                /**
                 * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual override onlyOwner {
                    _pendingOwner = newOwner;
                    emit OwnershipTransferStarted(owner(), newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual override {
                    delete _pendingOwner;
                    super._transferOwnership(newOwner);
                }
                /**
                 * @dev The new owner accepts the ownership transfer.
                 */
                function acceptOwnership() public virtual {
                    address sender = _msgSender();
                    require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
                    _transferOwnership(sender);
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[49] private __gap;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title IResolver
            /// @notice This contract acts as a bridge for name-to-address resolution.
            /// @custom:security-contact [email protected]
            interface IResolver {
                error RESOLVED_TO_ZERO_ADDRESS();
                /// @notice Resolves a name to its address deployed on a specified chain.
                /// @param _chainId The chainId of interest.
                /// @param _name Name whose address is to be resolved.
                /// @param _allowZeroAddress If set to true, does not throw if the resolved
                /// address is `address(0)`.
                /// @return Address associated with the given name on the specified
                /// chain.
                function resolve(
                    uint256 _chainId,
                    bytes32 _name,
                    bool _allowZeroAddress
                )
                    external
                    view
                    returns (address);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Interface of the ERC165 standard, as defined in the
             * https://eips.ethereum.org/EIPS/eip-165[EIP].
             *
             * Implementers can declare support of contract interfaces, which can then be
             * queried by others ({ERC165Checker}).
             *
             * For an implementation, see {ERC165}.
             */
            interface IERC165 {
                /**
                 * @dev Returns true if this contract implements the interface defined by
                 * `interfaceId`. See the corresponding
                 * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                 * to learn more about how these ids are created.
                 *
                 * This function call must use less than 30 000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool);
            }
            // 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.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
            pragma solidity ^0.8.2;
            import "../beacon/IBeacon.sol";
            import "../../interfaces/IERC1967.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._
             */
            abstract contract ERC1967Upgrade is IERC1967 {
                // 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 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 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 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 (last updated v4.9.0) (access/Ownable.sol)
            pragma solidity ^0.8.0;
            import "../utils/ContextUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
                address private _owner;
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                function __Ownable_init() internal onlyInitializing {
                    __Ownable_init_unchained();
                }
                function __Ownable_init_unchained() internal onlyInitializing {
                    _transferOwnership(_msgSender());
                }
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    _checkOwner();
                    _;
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    return _owner;
                }
                /**
                 * @dev Throws if the sender is not the owner.
                 */
                function _checkOwner() internal view virtual {
                    require(owner() == _msgSender(), "Ownable: caller is not the owner");
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby disabling any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    _transferOwnership(address(0));
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    require(newOwner != address(0), "Ownable: new owner is the zero address");
                    _transferOwnership(newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual {
                    address oldOwner = _owner;
                    _owner = newOwner;
                    emit OwnershipTransferred(oldOwner, newOwner);
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[49] private __gap;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
            pragma solidity ^0.8.2;
            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.
             *
             * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
             * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
             * case an upgrade adds a module that needs to be initialized.
             *
             * For example:
             *
             * [.hljs-theme-light.nopadding]
             * ```solidity
             * contract MyToken is ERC20Upgradeable {
             *     function initialize() initializer public {
             *         __ERC20_init("MyToken", "MTK");
             *     }
             * }
             *
             * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
             *     function initializeV2() reinitializer(2) public {
             *         __ERC20Permit_init("MyToken");
             *     }
             * }
             * ```
             *
             * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
             * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
             *
             * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
             * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
             *
             * [CAUTION]
             * ====
             * Avoid leaving a contract uninitialized.
             *
             * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
             * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
             * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
             *
             * [.hljs-theme-light.nopadding]
             * ```
             * /// @custom:oz-upgrades-unsafe-allow constructor
             * constructor() {
             *     _disableInitializers();
             * }
             * ```
             * ====
             */
            abstract contract Initializable {
                /**
                 * @dev Indicates that the contract has been initialized.
                 * @custom:oz-retyped-from bool
                 */
                uint8 private _initialized;
                /**
                 * @dev Indicates that the contract is in the process of being initialized.
                 */
                bool private _initializing;
                /**
                 * @dev Triggered when the contract has been initialized or reinitialized.
                 */
                event Initialized(uint8 version);
                /**
                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                 * `onlyInitializing` functions can be used to initialize parent contracts.
                 *
                 * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
                 * constructor.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier initializer() {
                    bool isTopLevelCall = !_initializing;
                    require(
                        (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                        "Initializable: contract is already initialized"
                    );
                    _initialized = 1;
                    if (isTopLevelCall) {
                        _initializing = true;
                    }
                    _;
                    if (isTopLevelCall) {
                        _initializing = false;
                        emit Initialized(1);
                    }
                }
                /**
                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                 * used to initialize parent contracts.
                 *
                 * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                 * are added through upgrades and that require initialization.
                 *
                 * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                 * cannot be nested. If one is invoked in the context of another, execution will revert.
                 *
                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                 * a contract, executing them in the right order is up to the developer or operator.
                 *
                 * WARNING: setting the version to 255 will prevent any future reinitialization.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier reinitializer(uint8 version) {
                    require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                    _initialized = version;
                    _initializing = true;
                    _;
                    _initializing = false;
                    emit Initialized(version);
                }
                /**
                 * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                 * {initializer} and {reinitializer} modifiers, directly or indirectly.
                 */
                modifier onlyInitializing() {
                    require(_initializing, "Initializable: contract is not initializing");
                    _;
                }
                /**
                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                 * through proxies.
                 *
                 * Emits an {Initialized} event the first time it is successfully executed.
                 */
                function _disableInitializers() internal virtual {
                    require(!_initializing, "Initializable: contract is initializing");
                    if (_initialized != type(uint8).max) {
                        _initialized = type(uint8).max;
                        emit Initialized(type(uint8).max);
                    }
                }
                /**
                 * @dev Returns the highest version that has been initialized. See {reinitializer}.
                 */
                function _getInitializedVersion() internal view returns (uint8) {
                    return _initialized;
                }
                /**
                 * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                 */
                function _isInitializing() internal view returns (bool) {
                    return _initializing;
                }
            }
            // 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.9.0) (interfaces/IERC1967.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
             *
             * _Available since v4.8.3._
             */
            interface IERC1967 {
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            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:
             * ```solidity
             * 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`, `uint256`._
             * _Available since v4.9 for `string`, `bytes`._
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes value;
                }
                /**
                 * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                 */
                function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                 */
                function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                 */
                function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                 */
                function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
            pragma solidity ^0.8.0;
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Provides information about the current execution context, including the
             * sender of the transaction and its data. While these are generally available
             * via msg.sender and msg.data, they should not be accessed in such a direct
             * manner, since when dealing with meta-transactions the account sending and
             * paying for execution may not be the actual sender (as far as an application
             * is concerned).
             *
             * This contract is only required for intermediate, library-like contracts.
             */
            abstract contract ContextUpgradeable is Initializable {
                function __Context_init() internal onlyInitializing {
                }
                function __Context_init_unchained() internal onlyInitializing {
                }
                function _msgSender() internal view virtual returns (address) {
                    return msg.sender;
                }
                function _msgData() internal view virtual returns (bytes calldata) {
                    return msg.data;
                }
                function _contextSuffixLength() internal view virtual returns (uint256) {
                    return 0;
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[50] private __gap;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            

            File 4 of 7: ERC1967Proxy
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.7.0) (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 initializing the storage of the proxy like a Solidity constructor.
                 */
                constructor(address _logic, bytes memory _data) payable {
                    _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.6.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 overridden 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 internal 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 overridden should call `super._beforeFallback()`.
                 */
                function _beforeFallback() internal virtual {}
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
            pragma solidity ^0.8.2;
            import "../beacon/IBeacon.sol";
            import "../../interfaces/IERC1967.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._
             */
            abstract contract ERC1967Upgrade is IERC1967 {
                // 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 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 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 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.9.0) (interfaces/IERC1967.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
             *
             * _Available since v4.8.3._
             */
            interface IERC1967 {
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            }
            // 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.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            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:
             * ```solidity
             * 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`, `uint256`._
             * _Available since v4.9 for `string`, `bytes`._
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes value;
                }
                /**
                 * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                 */
                function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                 */
                function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                 */
                function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                 */
                function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            

            File 5 of 7: ForcedInclusionStore
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "src/shared/common/EssentialContract.sol";
            import "src/shared/libs/LibMath.sol";
            import "src/shared/libs/LibAddress.sol";
            import "src/shared/libs/LibStrings.sol";
            import "src/layer1/based/ITaikoInbox.sol";
            import "./IForcedInclusionStore.sol";
            /// @title ForcedInclusionStore
            /// @dev A contract for storing and managing forced inclusion requests. Forced inclusions allow
            /// users to pay a fee to ensure their transactions are included in a block. The contract maintains
            /// a FIFO queue of inclusion requests.
            /// @custom:security-contact
            contract ForcedInclusionStore is EssentialContract, IForcedInclusionStore {
                using LibAddress for address;
                using LibMath for uint256;
                uint8 public immutable inclusionDelay; // measured in the number of batches
                uint64 public immutable feeInGwei;
                ITaikoInbox public immutable inbox;
                address public immutable inboxWrapper;
                mapping(uint256 id => ForcedInclusion inclusion) public queue; // slot 1
                uint64 public head; // slot 2
                uint64 public tail;
                uint64 public lastProcessedAtBatchId;
                uint64 private __reserved1;
                uint256[48] private __gap;
                // keccak256(abi.encode(uint256(keccak256("taiko.alethia.forcedinclusion.storage.TransactionGuard"))
                // - 1) & ~bytes32(uint256(0xff));
                bytes32 private constant _TRANSACTION_GUARD =
                    0x5a1e3a5f720a5155ea49503410bd539c2a6a2a71c3684875803b191fd01b8100;
                modifier onlyStandaloneTx() {
                    bytes32 guard;
                    assembly {
                        guard := tload(_TRANSACTION_GUARD)
                    }
                    require(guard == 0, MultipleCallsInOneTx());
                    assembly {
                        tstore(_TRANSACTION_GUARD, 1)
                    }
                    _;
                    // Will clean up at the end of the transaction
                }
                constructor(
                    uint8 _inclusionDelay,
                    uint64 _feeInGwei,
                    address _inbox,
                    address _inboxWrapper
                )
                    nonZeroValue(_inclusionDelay)
                    nonZeroValue(_feeInGwei)
                    nonZeroAddr(_inbox)
                    nonZeroAddr(_inboxWrapper)
                    EssentialContract(address(0))
                {
                    inclusionDelay = _inclusionDelay;
                    feeInGwei = _feeInGwei;
                    inbox = ITaikoInbox(_inbox);
                    inboxWrapper = _inboxWrapper;
                }
                function init(address _owner) external initializer {
                    __Essential_init(_owner);
                }
                function storeForcedInclusion(
                    uint8 blobIndex,
                    uint32 blobByteOffset,
                    uint32 blobByteSize
                )
                    external
                    payable
                    onlyStandaloneTx
                    whenNotPaused
                {
                    bytes32 blobHash = _blobHash(blobIndex);
                    require(blobHash != bytes32(0), BlobNotFound());
                    require(msg.value == feeInGwei * 1 gwei, IncorrectFee());
                    ForcedInclusion memory inclusion = ForcedInclusion({
                        blobHash: blobHash,
                        feeInGwei: uint64(msg.value / 1 gwei),
                        createdAtBatchId: _nextBatchId(),
                        blobByteOffset: blobByteOffset,
                        blobByteSize: blobByteSize,
                        blobCreatedIn: uint64(block.number)
                    });
                    queue[tail++] = inclusion;
                    emit ForcedInclusionStored(inclusion);
                }
                function consumeOldestForcedInclusion(address _feeRecipient)
                    external
                    onlyFrom(inboxWrapper)
                    nonReentrant
                    returns (ForcedInclusion memory inclusion_)
                {
                    // we only need to check the first one, since it will be the oldest.
                    ForcedInclusion storage inclusion = queue[head];
                    require(inclusion.createdAtBatchId != 0, NoForcedInclusionFound());
                    inclusion_ = inclusion;
                    lastProcessedAtBatchId = _nextBatchId();
                    unchecked {
                        delete queue[head++];
                        _feeRecipient.sendEtherAndVerify(inclusion_.feeInGwei * 1 gwei);
                    }
                    emit ForcedInclusionConsumed(inclusion_);
                }
                function getForcedInclusion(uint256 index) external view returns (ForcedInclusion memory) {
                    require(index >= head, InvalidIndex());
                    require(index < tail, InvalidIndex());
                    return queue[index];
                }
                function getOldestForcedInclusionDeadline() public view returns (uint256) {
                    if (head == tail) return type(uint256).max;
                    ForcedInclusion storage inclusion = queue[head];
                    if (inclusion.createdAtBatchId == 0) return type(uint256).max;
                    unchecked {
                        return uint256(lastProcessedAtBatchId).max(inclusion.createdAtBatchId) + inclusionDelay;
                    }
                }
                function isOldestForcedInclusionDue() external view returns (bool) {
                    uint256 deadline = getOldestForcedInclusionDeadline();
                    return deadline != type(uint256).max && _nextBatchId() >= deadline;
                }
                // @dev Override this function for easier testing blobs
                function _blobHash(uint8 blobIndex) internal view virtual returns (bytes32) {
                    return blobhash(blobIndex);
                }
                function _nextBatchId() private view returns (uint64) {
                    return inbox.getStats2().numBatches;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
            import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
            import "./IResolver.sol";
            /// @title EssentialContract
            /// @custom:security-contact [email protected]
            abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable {
                uint8 internal constant _FALSE = 1;
                uint8 internal constant _TRUE = 2;
                address private immutable __resolver;
                uint256[50] private __gapFromOldAddressResolver;
                /// @dev Slot 1.
                uint8 internal __reentry;
                uint8 internal __paused;
                uint256[49] private __gap;
                /// @notice Emitted when the contract is paused.
                /// @param account The account that paused the contract.
                event Paused(address account);
                /// @notice Emitted when the contract is unpaused.
                /// @param account The account that unpaused the contract.
                event Unpaused(address account);
                error INVALID_PAUSE_STATUS();
                error FUNC_NOT_IMPLEMENTED();
                error REENTRANT_CALL();
                error ACCESS_DENIED();
                error RESOLVER_NOT_FOUND();
                error ZERO_ADDRESS();
                error ZERO_VALUE();
                /// @dev Modifier that ensures the caller is the owner or resolved address of a given name.
                /// @param _name The name to check against.
                modifier onlyFromOwnerOrNamed(bytes32 _name) {
                    require(msg.sender == owner() || msg.sender == resolve(_name, true), ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is either the owner or a specified address.
                /// @param _addr The address to check against.
                modifier onlyFromOwnerOr(address _addr) {
                    require(msg.sender == owner() || msg.sender == _addr, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that reverts the function call, indicating it is not implemented.
                modifier notImplemented() {
                    revert FUNC_NOT_IMPLEMENTED();
                    _;
                }
                /// @dev Modifier that prevents reentrant calls to a function.
                modifier nonReentrant() {
                    require(_loadReentryLock() != _TRUE, REENTRANT_CALL());
                    _storeReentryLock(_TRUE);
                    _;
                    _storeReentryLock(_FALSE);
                }
                /// @dev Modifier that allows function execution only when the contract is paused.
                modifier whenPaused() {
                    require(paused(), INVALID_PAUSE_STATUS());
                    _;
                }
                /// @dev Modifier that allows function execution only when the contract is not paused.
                modifier whenNotPaused() {
                    require(!paused(), INVALID_PAUSE_STATUS());
                    _;
                }
                /// @dev Modifier that ensures the provided address is not the zero address.
                /// @param _addr The address to check.
                modifier nonZeroAddr(address _addr) {
                    require(_addr != address(0), ZERO_ADDRESS());
                    _;
                }
                /// @dev Modifier that ensures the provided value is not zero.
                /// @param _value The value to check.
                modifier nonZeroValue(uint256 _value) {
                    require(_value != 0, ZERO_VALUE());
                    _;
                }
                /// @dev Modifier that ensures the provided bytes32 value is not zero.
                /// @param _value The bytes32 value to check.
                modifier nonZeroBytes32(bytes32 _value) {
                    require(_value != 0, ZERO_VALUE());
                    _;
                }
                /// @dev Modifier that ensures the caller is the resolved address of a given
                /// name.
                /// @param _name The name to check against.
                modifier onlyFromNamed(bytes32 _name) {
                    require(msg.sender == resolve(_name, true), ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is the resolved address of a given
                /// name, if the name is set.
                /// @param _name The name to check against.
                modifier onlyFromOptionalNamed(bytes32 _name) {
                    address addr = resolve(_name, true);
                    require(addr == address(0) || msg.sender == addr, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is a resolved address to either _name1 or _name2
                /// name.
                /// @param _name1 The first name to check against.
                /// @param _name2 The second name to check against.
                modifier onlyFromNamedEither(bytes32 _name1, bytes32 _name2) {
                    require(
                        msg.sender == resolve(_name1, true) || msg.sender == resolve(_name2, true),
                        ACCESS_DENIED()
                    );
                    _;
                }
                /// @dev Modifier that ensures the caller is either of the two specified addresses.
                /// @param _addr1 The first address to check against.
                /// @param _addr2 The second address to check against.
                modifier onlyFromEither(address _addr1, address _addr2) {
                    require(msg.sender == _addr1 || msg.sender == _addr2, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is the specified address.
                /// @param _addr The address to check against.
                modifier onlyFrom(address _addr) {
                    require(msg.sender == _addr, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is the specified address.
                /// @param _addr The address to check against.
                modifier onlyFromOptional(address _addr) {
                    require(_addr == address(0) || msg.sender == _addr, ACCESS_DENIED());
                    _;
                }
                constructor(address _resolver) {
                    __resolver = _resolver;
                    _disableInitializers();
                }
                /// @notice Pauses the contract.
                function pause() public whenNotPaused {
                    _pause();
                    emit Paused(msg.sender);
                    // We call the authorize function here to avoid:
                    // Warning (5740): Unreachable code.
                    _authorizePause(msg.sender, true);
                }
                /// @notice Unpauses the contract.
                function unpause() public whenPaused {
                    _unpause();
                    emit Unpaused(msg.sender);
                    // We call the authorize function here to avoid:
                    // Warning (5740): Unreachable code.
                    _authorizePause(msg.sender, false);
                }
                function impl() public view returns (address) {
                    return _getImplementation();
                }
                /// @notice Returns true if the contract is paused, and false otherwise.
                /// @return true if paused, false otherwise.
                function paused() public view virtual returns (bool) {
                    return __paused == _TRUE;
                }
                function inNonReentrant() public view returns (bool) {
                    return _loadReentryLock() == _TRUE;
                }
                /// @notice Returns the address of this contract.
                /// @return The address of this contract.
                function resolver() public view virtual returns (address) {
                    return __resolver;
                }
                /// @notice Resolves a name to an address on a specific chain
                /// @param _chainId The chain ID to resolve the name on
                /// @param _name The name to resolve
                /// @param _allowZeroAddress Whether to allow resolving to the zero address
                /// @return The resolved address
                function resolve(
                    uint64 _chainId,
                    bytes32 _name,
                    bool _allowZeroAddress
                )
                    internal
                    view
                    returns (address)
                {
                    return IResolver(resolver()).resolve(_chainId, _name, _allowZeroAddress);
                }
                /// @notice Resolves a name to an address on the current chain
                /// @param _name The name to resolve
                /// @param _allowZeroAddress Whether to allow resolving to the zero address
                /// @return The resolved address
                function resolve(bytes32 _name, bool _allowZeroAddress) internal view returns (address) {
                    return IResolver(resolver()).resolve(block.chainid, _name, _allowZeroAddress);
                }
                /// @notice Initializes the contract.
                /// @param _owner The owner of this contract. msg.sender will be used if this value is zero.
                function __Essential_init(address _owner) internal virtual onlyInitializing {
                    __Context_init();
                    _transferOwnership(_owner == address(0) ? msg.sender : _owner);
                    __paused = _FALSE;
                }
                function _pause() internal virtual {
                    __paused = _TRUE;
                }
                function _unpause() internal virtual {
                    __paused = _FALSE;
                }
                function _authorizeUpgrade(address) internal virtual override onlyOwner { }
                function _authorizePause(address, bool) internal virtual onlyOwner { }
                // Stores the reentry lock
                function _storeReentryLock(uint8 _reentry) internal virtual {
                    __reentry = _reentry;
                }
                // Loads the reentry lock
                function _loadReentryLock() internal view virtual returns (uint8 reentry_) {
                    reentry_ = __reentry;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title LibMath
            /// @dev This library offers additional math functions for uint256.
            /// @custom:security-contact [email protected]
            library LibMath {
                /// @dev Returns the smaller of the two given values.
                /// @param _a The first number to compare.
                /// @param _b The second number to compare.
                /// @return The smaller of the two numbers.
                function min(uint256 _a, uint256 _b) internal pure returns (uint256) {
                    return _a > _b ? _b : _a;
                }
                /// @dev Returns the larger of the two given values.
                /// @param _a The first number to compare.
                /// @param _b The second number to compare.
                /// @return The larger of the two numbers.
                function max(uint256 _a, uint256 _b) internal pure returns (uint256) {
                    return _a > _b ? _a : _b;
                }
                function capToUint64(uint256 _value) internal pure returns (uint64) {
                    return uint64(min(_value, type(uint64).max));
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
            /// @title LibAddress
            /// @dev Provides utilities for address-related operations.
            /// @custom:security-contact [email protected]
            library LibAddress {
                error ETH_TRANSFER_FAILED();
                /// @dev Sends Ether to the specified address. This method will not revert even if sending ether
                /// fails.
                /// This function is inspired by
                /// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol
                /// @param _to The recipient address.
                /// @param _amount The amount of Ether to send in wei.
                /// @param _gasLimit The max amount gas to pay for this transaction.
                /// @return success_ true if the call is successful, false otherwise.
                function sendEther(
                    address _to,
                    uint256 _amount,
                    uint256 _gasLimit,
                    bytes memory _calldata
                )
                    internal
                    returns (bool success_)
                {
                    // Check for zero-address transactions
                    require(_to != address(0), ETH_TRANSFER_FAILED());
                    // dispatch message to recipient
                    // by assembly calling "handle" function
                    // we call via assembly to avoid memcopying a very large returndata
                    // returned by a malicious contract
                    assembly {
                        success_ :=
                            call(
                                _gasLimit, // gas
                                _to, // recipient
                                _amount, // ether value
                                add(_calldata, 0x20), // inloc
                                mload(_calldata), // inlen
                                0, // outloc
                                0 // outlen
                            )
                    }
                }
                /// @dev Sends Ether to the specified address. This method will revert if sending ether fails.
                /// @param _to The recipient address.
                /// @param _amount The amount of Ether to send in wei.
                /// @param _gasLimit The max amount gas to pay for this transaction.
                function sendEtherAndVerify(address _to, uint256 _amount, uint256 _gasLimit) internal {
                    if (_amount == 0) return;
                    require(sendEther(_to, _amount, _gasLimit, ""), ETH_TRANSFER_FAILED());
                }
                /// @dev Sends Ether to the specified address. This method will revert if sending ether fails.
                /// @param _to The recipient address.
                /// @param _amount The amount of Ether to send in wei.
                function sendEtherAndVerify(address _to, uint256 _amount) internal {
                    sendEtherAndVerify(_to, _amount, gasleft());
                }
                function supportsInterface(
                    address _addr,
                    bytes4 _interfaceId
                )
                    internal
                    view
                    returns (bool result_)
                {
                    (bool success, bytes memory data) =
                        _addr.staticcall(abi.encodeCall(IERC165.supportsInterface, (_interfaceId)));
                    if (success && data.length == 32) {
                        result_ = abi.decode(data, (bool));
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title LibStrings
            /// @custom:security-contact [email protected]
            library LibStrings {
                bytes32 internal constant B_AUTOMATA_DCAP_ATTESTATION = bytes32("automata_dcap_attestation");
                bytes32 internal constant B_SGX_GETH_AUTOMATA = bytes32("sgx_geth_automata");
                bytes32 internal constant B_BOND_TOKEN = bytes32("bond_token");
                bytes32 internal constant B_BRIDGE = bytes32("bridge");
                bytes32 internal constant B_BRIDGE_WATCHDOG = bytes32("bridge_watchdog");
                bytes32 internal constant B_BRIDGED_ERC1155 = bytes32("bridged_erc1155");
                bytes32 internal constant B_BRIDGED_ERC20 = bytes32("bridged_erc20");
                bytes32 internal constant B_BRIDGED_ERC721 = bytes32("bridged_erc721");
                bytes32 internal constant B_CHAIN_WATCHDOG = bytes32("chain_watchdog");
                bytes32 internal constant B_ERC1155_VAULT = bytes32("erc1155_vault");
                bytes32 internal constant B_ERC20_VAULT = bytes32("erc20_vault");
                bytes32 internal constant B_ERC721_VAULT = bytes32("erc721_vault");
                bytes32 internal constant B_FORCED_INCLUSION_STORE = bytes32("forced_inclusion_store");
                bytes32 internal constant B_PRECONF_WHITELIST = bytes32("preconf_whitelist");
                bytes32 internal constant B_PRECONF_WHITELIST_OWNER = bytes32("preconf_whitelist_owner");
                bytes32 internal constant B_PRECONF_ROUTER = bytes32("preconf_router");
                bytes32 internal constant B_TAIKO_WRAPPER = bytes32("taiko_wrapper");
                bytes32 internal constant B_PROOF_VERIFIER = bytes32("proof_verifier");
                bytes32 internal constant B_SGX_RETH_VERIFIER = bytes32("sgx_reth_verifier");
                bytes32 internal constant B_SGX_GETH_VERIFIER = bytes32("sgx_geth_verifier");
                bytes32 internal constant B_RISC0_RETH_VERIFIER = bytes32("risc0_reth_verifier");
                bytes32 internal constant B_SP1_RETH_VERIFIER = bytes32("sp1_reth_verifier");
                bytes32 internal constant B_PROVER_SET = bytes32("prover_set");
                bytes32 internal constant B_QUOTA_MANAGER = bytes32("quota_manager");
                bytes32 internal constant B_SIGNAL_SERVICE = bytes32("signal_service");
                bytes32 internal constant B_TAIKO = bytes32("taiko");
                bytes32 internal constant B_TAIKO_TOKEN = bytes32("taiko_token");
                bytes32 internal constant B_WITHDRAWER = bytes32("withdrawer");
                bytes32 internal constant H_SIGNAL_ROOT = keccak256("SIGNAL_ROOT");
                bytes32 internal constant H_STATE_ROOT = keccak256("STATE_ROOT");
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "src/shared/based/LibSharedData.sol";
            /// @title TaikoInbox
            /// @notice Acts as the inbox for the Taiko Alethia protocol, a simplified version of the
            /// original Taiko-Based Contestable Rollup (BCR). The tier-based proof system and
            /// contestation mechanisms have been removed.
            ///
            /// Key assumptions of this protocol:
            /// - Block proposals and proofs are asynchronous. Proofs are not available at proposal time,
            ///   unlike Taiko Gwyneth, which assumes synchronous composability.
            /// - Proofs are presumed error-free and thoroughly validated, with proof type management
            ///   delegated to IVerifier contracts.
            ///
            /// @dev Registered in the address resolver as "taiko".
            /// @custom:security-contact [email protected]
            interface ITaikoInbox {
                struct BlockParams {
                    // the max number of transactions in this block. Note that if there are not enough
                    // transactions in calldata or blobs, the block will contains as many transactions as
                    // possible.
                    uint16 numTransactions;
                    // The time difference (in seconds) between the timestamp of this block and
                    // the timestamp of the parent block in the same batch. For the first block in a batch,
                    // there is not parent block in the same batch, so the time shift should be 0.
                    uint8 timeShift;
                    // Signals sent on L1 and need to sync to this L2 block.
                    bytes32[] signalSlots;
                }
                struct BlobParams {
                    // The hashes of the blob. Note that if this array is not empty.  `firstBlobIndex` and
                    // `numBlobs` must be 0.
                    bytes32[] blobHashes;
                    // The index of the first blob in this batch.
                    uint8 firstBlobIndex;
                    // The number of blobs in this batch. Blobs are initially concatenated and subsequently
                    // decompressed via Zlib.
                    uint8 numBlobs;
                    // The byte offset of the blob in the batch.
                    uint32 byteOffset;
                    // The byte size of the blob.
                    uint32 byteSize;
                    // The block number when the blob was created. This value is only non-zero when
                    // `blobHashes` are non-empty.
                    uint64 createdIn;
                }
                struct BatchParams {
                    address proposer;
                    address coinbase;
                    bytes32 parentMetaHash;
                    uint64 anchorBlockId;
                    uint64 lastBlockTimestamp;
                    bool revertIfNotFirstProposal;
                    // Specifies the number of blocks to be generated from this batch.
                    BlobParams blobParams;
                    BlockParams[] blocks;
                }
                /// @dev This struct holds batch information essential for constructing blocks offchain, but it
                /// does not include data necessary for batch proving.
                struct BatchInfo {
                    bytes32 txsHash;
                    // Data to build L2 blocks
                    BlockParams[] blocks;
                    bytes32[] blobHashes;
                    bytes32 extraData;
                    address coinbase;
                    uint64 proposedIn; // Used by node/client
                    uint64 blobCreatedIn;
                    uint32 blobByteOffset;
                    uint32 blobByteSize;
                    uint32 gasLimit;
                    uint64 lastBlockId;
                    uint64 lastBlockTimestamp;
                    // Data for the L2 anchor transaction, shared by all blocks in the batch
                    uint64 anchorBlockId;
                    // corresponds to the `_anchorStateRoot` parameter in the anchor transaction.
                    // The batch's validity proof shall verify the integrity of these two values.
                    bytes32 anchorBlockHash;
                    LibSharedData.BaseFeeConfig baseFeeConfig;
                }
                /// @dev This struct holds batch metadata essential for proving the batch.
                struct BatchMetadata {
                    bytes32 infoHash;
                    address proposer;
                    uint64 batchId;
                    uint64 proposedAt; // Used by node/client
                }
                /// @notice Struct representing transition to be proven.
                struct Transition {
                    bytes32 parentHash;
                    bytes32 blockHash;
                    bytes32 stateRoot;
                }
                //  @notice Struct representing transition storage
                /// @notice 4 slots used.
                struct TransitionState {
                    bytes32 parentHash;
                    bytes32 blockHash;
                    bytes32 stateRoot;
                    address prover;
                    bool inProvingWindow;
                    uint48 createdAt;
                }
                /// @notice 3 slots used.
                struct Batch {
                    bytes32 metaHash; // slot 1
                    uint64 lastBlockId; // slot 2
                    uint96 reserved3;
                    uint96 livenessBond;
                    uint64 batchId; // slot 3
                    uint64 lastBlockTimestamp;
                    uint64 anchorBlockId;
                    uint24 nextTransitionId;
                    uint8 reserved4;
                    // The ID of the transaction that is used to verify this batch. However, if this batch is
                    // not verified as the last one in a transaction, verifiedTransitionId will remain zero.
                    uint24 verifiedTransitionId;
                }
                /// @notice Forge is only able to run coverage in case the contracts by default capable of
                /// compiling without any optimization (neither optimizer runs, no compiling --via-ir flag).
                struct Stats1 {
                    uint64 genesisHeight;
                    uint64 __reserved2;
                    uint64 lastSyncedBatchId;
                    uint64 lastSyncedAt;
                }
                struct Stats2 {
                    uint64 numBatches;
                    uint64 lastVerifiedBatchId;
                    bool paused;
                    uint56 lastProposedIn;
                    uint64 lastUnpausedAt;
                }
                struct ForkHeights {
                    uint64 ontake; // measured with block number.
                    uint64 pacaya; // measured with the batch Id, not block number.
                    uint64 shasta; // measured with the batch Id, not block number.
                    uint64 unzen; // measured with the batch Id, not block number.
                }
                /// @notice Struct holding Taiko configuration parameters. See {TaikoConfig}.
                struct Config {
                    /// @notice The chain ID of the network where Taiko contracts are deployed.
                    uint64 chainId;
                    /// @notice The maximum number of unverified batches the protocol supports.
                    uint64 maxUnverifiedBatches;
                    /// @notice Size of the batch ring buffer, allowing extra space for proposals.
                    uint64 batchRingBufferSize;
                    /// @notice The maximum number of verifications allowed when a batch is proposed or proved.
                    uint64 maxBatchesToVerify;
                    /// @notice The maximum gas limit allowed for a block.
                    uint32 blockMaxGasLimit;
                    /// @notice The amount of Taiko token as a prover liveness bond per batch.
                    uint96 livenessBondBase;
                    /// @notice The amount of Taiko token as a prover liveness bond per block. This field is
                    /// deprecated and its value will be ignored.
                    uint96 livenessBondPerBlock;
                    /// @notice The number of batches between two L2-to-L1 state root sync.
                    uint8 stateRootSyncInternal;
                    /// @notice The max differences of the anchor height and the current block number.
                    uint64 maxAnchorHeightOffset;
                    /// @notice Base fee configuration
                    LibSharedData.BaseFeeConfig baseFeeConfig;
                    /// @notice The proving window in seconds.
                    uint16 provingWindow;
                    /// @notice The time required for a transition to be used for verifying a batch.
                    uint24 cooldownWindow;
                    /// @notice The maximum number of signals to be received by TaikoL2.
                    uint8 maxSignalsToReceive;
                    /// @notice The maximum number of blocks per batch.
                    uint16 maxBlocksPerBatch;
                    /// @notice Historical heights of the forks.
                    ForkHeights forkHeights;
                }
                /// @notice Struct holding the state variables for the {Taiko} contract.
                struct State {
                    // Ring buffer for proposed batches and a some recent verified batches.
                    mapping(uint256 batchId_mod_batchRingBufferSize => Batch batch) batches;
                    // Indexing to transition ids (ring buffer not possible)
                    mapping(uint256 batchId => mapping(bytes32 parentHash => uint24 transitionId)) transitionIds;
                    // Ring buffer for transitions
                    mapping(
                        uint256 batchId_mod_batchRingBufferSize
                            => mapping(uint24 transitionId => TransitionState ts)
                    ) transitions;
                    bytes32 __reserve1; // slot 4 - was used as a ring buffer for Ether deposits
                    Stats1 stats1; // slot 5
                    Stats2 stats2; // slot 6
                    mapping(address account => uint256 bond) bondBalance;
                    uint256[43] __gap;
                }
                /// @notice Emitted when tokens are deposited into a user's bond balance.
                /// @param user The address of the user who deposited the tokens.
                /// @param amount The amount of tokens deposited.
                event BondDeposited(address indexed user, uint256 amount);
                /// @notice Emitted when tokens are withdrawn from a user's bond balance.
                /// @param user The address of the user who withdrew the tokens.
                /// @param amount The amount of tokens withdrawn.
                event BondWithdrawn(address indexed user, uint256 amount);
                /// @notice Emitted when a token is credited back to a user's bond balance.
                /// @param user The address of the user whose bond balance is credited.
                /// @param amount The amount of tokens credited.
                event BondCredited(address indexed user, uint256 amount);
                /// @notice Emitted when a token is debited from a user's bond balance.
                /// @param user The address of the user whose bond balance is debited.
                /// @param amount The amount of tokens debited.
                event BondDebited(address indexed user, uint256 amount);
                /// @notice Emitted when a batch is synced.
                /// @param stats1 The Stats1 data structure.
                event Stats1Updated(Stats1 stats1);
                /// @notice Emitted when some state variable values changed.
                /// @param stats2 The Stats2 data structure.
                event Stats2Updated(Stats2 stats2);
                /// @notice Emitted when a batch is proposed.
                /// @param info The info of the proposed batch.
                /// @param meta The metadata of the proposed batch.
                /// @param txList The tx list in calldata.
                event BatchProposed(BatchInfo info, BatchMetadata meta, bytes txList);
                /// @notice Emitted when multiple transitions are proved.
                /// @param verifier The address of the verifier.
                /// @param transitions The transitions data.
                event BatchesProved(address verifier, uint64[] batchIds, Transition[] transitions);
                /// @notice Emitted when a transition is overwritten by a conflicting one with the same parent
                /// hash but different block hash or state root.
                /// @param batchId The batch ID.
                /// @param oldTran The old transition overwritten.
                /// @param newTran The new transition.
                event ConflictingProof(uint64 batchId, TransitionState oldTran, Transition newTran);
                /// @notice Emitted when a batch is verified.
                /// @param batchId The ID of the verified batch.
                /// @param blockHash The hash of the verified batch.
                event BatchesVerified(uint64 batchId, bytes32 blockHash);
                error AnchorBlockIdSmallerThanParent();
                error AnchorBlockIdTooLarge();
                error AnchorBlockIdTooSmall();
                error ArraySizesMismatch();
                error BatchNotFound();
                error BatchVerified();
                error BeyondCurrentFork();
                error BlobNotFound();
                error BlockNotFound();
                error BlobNotSpecified();
                error ContractPaused();
                error CustomProposerMissing();
                error CustomProposerNotAllowed();
                error EtherNotPaidAsBond();
                error FirstBlockTimeShiftNotZero();
                error ForkNotActivated();
                error InsufficientBond();
                error InvalidBlobCreatedIn();
                error InvalidBlobParams();
                error InvalidGenesisBlockHash();
                error InvalidParams();
                error InvalidTransitionBlockHash();
                error InvalidTransitionParentHash();
                error InvalidTransitionStateRoot();
                error MetaHashMismatch();
                error MsgValueNotZero();
                error NoBlocksToProve();
                error NotFirstProposal();
                error NotInboxWrapper();
                error ParentMetaHashMismatch();
                error SameTransition();
                error SignalNotSent();
                error TimestampSmallerThanParent();
                error TimestampTooLarge();
                error TimestampTooSmall();
                error TooManyBatches();
                error TooManyBlocks();
                error TooManySignals();
                error TransitionNotFound();
                error ZeroAnchorBlockHash();
                /// @notice Proposes a batch of blocks.
                /// @param _params ABI-encoded parameters.
                /// @param _txList The transaction list in calldata. If the txList is empty, blob will be used
                /// for data availability.
                /// @return info_ The info of the proposed batch.
                /// @return meta_ The metadata of the proposed batch.
                function proposeBatch(
                    bytes calldata _params,
                    bytes calldata _txList
                )
                    external
                    returns (ITaikoInbox.BatchInfo memory info_, ITaikoInbox.BatchMetadata memory meta_);
                /// @notice Proves state transitions for multiple batches with a single aggregated proof.
                /// @param _params ABI-encoded parameter containing:
                /// - metas: Array of metadata for each batch being proved.
                /// - transitions: Array of batch transitions to be proved.
                /// @param _proof The aggregated cryptographic proof proving the batches transitions.
                function proveBatches(bytes calldata _params, bytes calldata _proof) external;
                /// @notice Deposits TAIKO tokens into the contract to be used as liveness bond.
                /// @param _amount The amount of TAIKO tokens to deposit.
                function depositBond(uint256 _amount) external payable;
                /// @notice Withdraws a specified amount of TAIKO tokens from the contract.
                /// @param _amount The amount of TAIKO tokens to withdraw.
                function withdrawBond(uint256 _amount) external;
                /// @notice Returns the TAIKO token balance of a specific user.
                /// @param _user The address of the user.
                /// @return The TAIKO token balance of the user.
                function bondBalanceOf(address _user) external view returns (uint256);
                /// @notice Retrieves the Bond token address. If Ether is used as bond, this function returns
                /// address(0).
                /// @return The Bond token address.
                function bondToken() external view returns (address);
                /// @notice Retrieves the first set of protocol statistics.
                /// @return Stats1 structure containing the statistics.
                function getStats1() external view returns (Stats1 memory);
                /// @notice Retrieves the second set of protocol statistics.
                /// @return Stats2 structure containing the statistics.
                function getStats2() external view returns (Stats2 memory);
                /// @notice Retrieves data about a specific batch.
                /// @param _batchId The ID of the batch to retrieve.
                /// @return batch_ The batch data.
                function getBatch(uint64 _batchId) external view returns (Batch memory batch_);
                /// @notice Retrieves a specific transition by batch ID and transition ID. This function may
                /// revert if the transition is not found.
                /// @param _batchId The batch ID.
                /// @param _tid The transition ID.
                /// @return The specified transition state.
                function getTransitionById(
                    uint64 _batchId,
                    uint24 _tid
                )
                    external
                    view
                    returns (ITaikoInbox.TransitionState memory);
                /// @notice Retrieves a specific transition by batch ID and parent Hash. This function may
                /// revert if the transition is not found.
                /// @param _batchId The batch ID.
                /// @param _parentHash The parent hash.
                /// @return The specified transition state.
                function getTransitionByParentHash(
                    uint64 _batchId,
                    bytes32 _parentHash
                )
                    external
                    view
                    returns (ITaikoInbox.TransitionState memory);
                /// @notice Retrieves the transition used for the last verified batch.
                /// @return batchId_ The batch ID of the last verified transition.
                /// @return blockId_ The block ID of the last verified block.
                /// @return ts_ The last verified transition.
                function getLastVerifiedTransition()
                    external
                    view
                    returns (uint64 batchId_, uint64 blockId_, TransitionState memory ts_);
                /// @notice Retrieves the transition used for the last synced batch.
                /// @return batchId_ The batch ID of the last synced transition.
                /// @return blockId_ The block ID of the last synced block.
                /// @return ts_ The last synced transition.
                function getLastSyncedTransition()
                    external
                    view
                    returns (uint64 batchId_, uint64 blockId_, TransitionState memory ts_);
                /// @notice Retrieves the transition used for verifying a batch.
                /// @param _batchId The batch ID.
                /// @return The transition used for verifying the batch.
                function getBatchVerifyingTransition(uint64 _batchId)
                    external
                    view
                    returns (TransitionState memory);
                /// @notice Retrieves the current protocol configuration.
                /// @return The current configuration.
                function pacayaConfig() external view returns (Config memory);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title IForcedInclusionStore
            /// @custom:security-contact [email protected]
            interface IForcedInclusionStore {
                struct ForcedInclusion {
                    bytes32 blobHash;
                    uint64 feeInGwei;
                    uint64 createdAtBatchId;
                    uint32 blobByteOffset;
                    uint32 blobByteSize;
                    uint64 blobCreatedIn;
                }
                /// @dev Event emitted when a forced inclusion is stored.
                event ForcedInclusionStored(ForcedInclusion forcedInclusion);
                /// @dev Event emitted when a forced inclusion is consumed.
                event ForcedInclusionConsumed(ForcedInclusion forcedInclusion);
                /// @dev Error thrown when a blob is not found.
                error BlobNotFound();
                /// @dev Error thrown when the parameters are invalid.
                error InvalidParams();
                /// @dev Error thrown when the fee is incorrect.
                error IncorrectFee();
                /// @dev Error thrown when the index is invalid.
                error InvalidIndex();
                /// @dev Error thrown when a forced inclusion is not found.
                error NoForcedInclusionFound();
                /// @dev Error thrown when a function is called more than once in one transaction.
                error MultipleCallsInOneTx();
                /// @dev Retrieve a forced inclusion request by its index.
                /// @param index The index of the forced inclusion request in the queue.
                /// @return The forced inclusion request at the specified index.
                function getForcedInclusion(uint256 index) external view returns (ForcedInclusion memory);
                /// @dev Get the deadline for the oldest forced inclusion.
                /// @return The deadline for the oldest forced inclusion.
                function getOldestForcedInclusionDeadline() external view returns (uint256);
                /// @dev Check if the oldest forced inclusion is due.
                /// @return True if the oldest forced inclusion is due, false otherwise.
                function isOldestForcedInclusionDue() external view returns (bool);
                /// @dev Consume a forced inclusion request.
                /// The inclusion request must be marked as processed and the priority fee must be paid to the
                /// caller.
                /// @param _feeRecipient The address to receive the priority fee.
                /// @return inclusion_ The forced inclusion request.
                function consumeOldestForcedInclusion(address _feeRecipient)
                    external
                    returns (ForcedInclusion memory);
                /// @dev Store a forced inclusion request.
                /// The priority fee must be paid to the contract.
                /// @param blobIndex The index of the blob that contains the transaction data.
                /// @param blobByteOffset The byte offset in the blob
                /// @param blobByteSize The size of the blob in bytes
                function storeForcedInclusion(
                    uint8 blobIndex,
                    uint32 blobByteOffset,
                    uint32 blobByteSize
                )
                    external
                    payable;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
            pragma solidity ^0.8.0;
            import "../../interfaces/draft-IERC1822.sol";
            import "../ERC1967/ERC1967Upgrade.sol";
            /**
             * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
             * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
             *
             * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
             * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
             * `UUPSUpgradeable` with a custom implementation of upgrades.
             *
             * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
             *
             * _Available since v4.1._
             */
            abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
                /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
                address private immutable __self = address(this);
                /**
                 * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
                 * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
                 * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
                 * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
                 * fail.
                 */
                modifier onlyProxy() {
                    require(address(this) != __self, "Function must be called through delegatecall");
                    require(_getImplementation() == __self, "Function must be called through active proxy");
                    _;
                }
                /**
                 * @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, "UUPSUpgradeable: must not be called through delegatecall");
                    _;
                }
                /**
                 * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
                 * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                 *
                 * 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. This is guaranteed by the `notDelegated` modifier.
                 */
                function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
                    return _IMPLEMENTATION_SLOT;
                }
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeTo(address newImplementation) public virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
                }
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                 * encoded in `data`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, data, true);
                }
                /**
                 * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                 * {upgradeTo} and {upgradeToAndCall}.
                 *
                 * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                 *
                 * ```solidity
                 * function _authorizeUpgrade(address) internal override onlyOwner {}
                 * ```
                 */
                function _authorizeUpgrade(address newImplementation) internal virtual;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
            pragma solidity ^0.8.0;
            import "./OwnableUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which provides access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership} and {acceptOwnership}.
             *
             * This module is used through inheritance. It will make available all functions
             * from parent (Ownable).
             */
            abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
                address private _pendingOwner;
                event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
                function __Ownable2Step_init() internal onlyInitializing {
                    __Ownable_init_unchained();
                }
                function __Ownable2Step_init_unchained() internal onlyInitializing {
                }
                /**
                 * @dev Returns the address of the pending owner.
                 */
                function pendingOwner() public view virtual returns (address) {
                    return _pendingOwner;
                }
                /**
                 * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual override onlyOwner {
                    _pendingOwner = newOwner;
                    emit OwnershipTransferStarted(owner(), newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual override {
                    delete _pendingOwner;
                    super._transferOwnership(newOwner);
                }
                /**
                 * @dev The new owner accepts the ownership transfer.
                 */
                function acceptOwnership() public virtual {
                    address sender = _msgSender();
                    require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
                    _transferOwnership(sender);
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[49] private __gap;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title IResolver
            /// @notice This contract acts as a bridge for name-to-address resolution.
            /// @custom:security-contact [email protected]
            interface IResolver {
                error RESOLVED_TO_ZERO_ADDRESS();
                /// @notice Resolves a name to its address deployed on a specified chain.
                /// @param _chainId The chainId of interest.
                /// @param _name Name whose address is to be resolved.
                /// @param _allowZeroAddress If set to true, does not throw if the resolved
                /// address is `address(0)`.
                /// @return Address associated with the given name on the specified
                /// chain.
                function resolve(
                    uint256 _chainId,
                    bytes32 _name,
                    bool _allowZeroAddress
                )
                    external
                    view
                    returns (address);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Interface of the ERC165 standard, as defined in the
             * https://eips.ethereum.org/EIPS/eip-165[EIP].
             *
             * Implementers can declare support of contract interfaces, which can then be
             * queried by others ({ERC165Checker}).
             *
             * For an implementation, see {ERC165}.
             */
            interface IERC165 {
                /**
                 * @dev Returns true if this contract implements the interface defined by
                 * `interfaceId`. See the corresponding
                 * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                 * to learn more about how these ids are created.
                 *
                 * This function call must use less than 30 000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            library LibSharedData {
                /// @dev Struct that represents L2 basefee configurations
                struct BaseFeeConfig {
                    uint8 adjustmentQuotient;
                    uint8 sharingPctg;
                    uint32 gasIssuancePerSecond;
                    uint64 minGasExcess;
                    uint32 maxGasIssuancePerBlock;
                }
            }
            // 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.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
            pragma solidity ^0.8.2;
            import "../beacon/IBeacon.sol";
            import "../../interfaces/IERC1967.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._
             */
            abstract contract ERC1967Upgrade is IERC1967 {
                // 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 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 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 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 (last updated v4.9.0) (access/Ownable.sol)
            pragma solidity ^0.8.0;
            import "../utils/ContextUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
                address private _owner;
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                function __Ownable_init() internal onlyInitializing {
                    __Ownable_init_unchained();
                }
                function __Ownable_init_unchained() internal onlyInitializing {
                    _transferOwnership(_msgSender());
                }
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    _checkOwner();
                    _;
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    return _owner;
                }
                /**
                 * @dev Throws if the sender is not the owner.
                 */
                function _checkOwner() internal view virtual {
                    require(owner() == _msgSender(), "Ownable: caller is not the owner");
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby disabling any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    _transferOwnership(address(0));
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    require(newOwner != address(0), "Ownable: new owner is the zero address");
                    _transferOwnership(newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual {
                    address oldOwner = _owner;
                    _owner = newOwner;
                    emit OwnershipTransferred(oldOwner, newOwner);
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[49] private __gap;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
            pragma solidity ^0.8.2;
            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.
             *
             * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
             * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
             * case an upgrade adds a module that needs to be initialized.
             *
             * For example:
             *
             * [.hljs-theme-light.nopadding]
             * ```solidity
             * contract MyToken is ERC20Upgradeable {
             *     function initialize() initializer public {
             *         __ERC20_init("MyToken", "MTK");
             *     }
             * }
             *
             * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
             *     function initializeV2() reinitializer(2) public {
             *         __ERC20Permit_init("MyToken");
             *     }
             * }
             * ```
             *
             * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
             * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
             *
             * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
             * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
             *
             * [CAUTION]
             * ====
             * Avoid leaving a contract uninitialized.
             *
             * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
             * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
             * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
             *
             * [.hljs-theme-light.nopadding]
             * ```
             * /// @custom:oz-upgrades-unsafe-allow constructor
             * constructor() {
             *     _disableInitializers();
             * }
             * ```
             * ====
             */
            abstract contract Initializable {
                /**
                 * @dev Indicates that the contract has been initialized.
                 * @custom:oz-retyped-from bool
                 */
                uint8 private _initialized;
                /**
                 * @dev Indicates that the contract is in the process of being initialized.
                 */
                bool private _initializing;
                /**
                 * @dev Triggered when the contract has been initialized or reinitialized.
                 */
                event Initialized(uint8 version);
                /**
                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                 * `onlyInitializing` functions can be used to initialize parent contracts.
                 *
                 * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
                 * constructor.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier initializer() {
                    bool isTopLevelCall = !_initializing;
                    require(
                        (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                        "Initializable: contract is already initialized"
                    );
                    _initialized = 1;
                    if (isTopLevelCall) {
                        _initializing = true;
                    }
                    _;
                    if (isTopLevelCall) {
                        _initializing = false;
                        emit Initialized(1);
                    }
                }
                /**
                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                 * used to initialize parent contracts.
                 *
                 * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                 * are added through upgrades and that require initialization.
                 *
                 * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                 * cannot be nested. If one is invoked in the context of another, execution will revert.
                 *
                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                 * a contract, executing them in the right order is up to the developer or operator.
                 *
                 * WARNING: setting the version to 255 will prevent any future reinitialization.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier reinitializer(uint8 version) {
                    require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                    _initialized = version;
                    _initializing = true;
                    _;
                    _initializing = false;
                    emit Initialized(version);
                }
                /**
                 * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                 * {initializer} and {reinitializer} modifiers, directly or indirectly.
                 */
                modifier onlyInitializing() {
                    require(_initializing, "Initializable: contract is not initializing");
                    _;
                }
                /**
                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                 * through proxies.
                 *
                 * Emits an {Initialized} event the first time it is successfully executed.
                 */
                function _disableInitializers() internal virtual {
                    require(!_initializing, "Initializable: contract is initializing");
                    if (_initialized != type(uint8).max) {
                        _initialized = type(uint8).max;
                        emit Initialized(type(uint8).max);
                    }
                }
                /**
                 * @dev Returns the highest version that has been initialized. See {reinitializer}.
                 */
                function _getInitializedVersion() internal view returns (uint8) {
                    return _initialized;
                }
                /**
                 * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                 */
                function _isInitializing() internal view returns (bool) {
                    return _initializing;
                }
            }
            // 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.9.0) (interfaces/IERC1967.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
             *
             * _Available since v4.8.3._
             */
            interface IERC1967 {
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            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:
             * ```solidity
             * 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`, `uint256`._
             * _Available since v4.9 for `string`, `bytes`._
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes value;
                }
                /**
                 * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                 */
                function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                 */
                function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                 */
                function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                 */
                function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
            pragma solidity ^0.8.0;
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Provides information about the current execution context, including the
             * sender of the transaction and its data. While these are generally available
             * via msg.sender and msg.data, they should not be accessed in such a direct
             * manner, since when dealing with meta-transactions the account sending and
             * paying for execution may not be the actual sender (as far as an application
             * is concerned).
             *
             * This contract is only required for intermediate, library-like contracts.
             */
            abstract contract ContextUpgradeable is Initializable {
                function __Context_init() internal onlyInitializing {
                }
                function __Context_init_unchained() internal onlyInitializing {
                }
                function _msgSender() internal view virtual returns (address) {
                    return msg.sender;
                }
                function _msgData() internal view virtual returns (bytes calldata) {
                    return msg.data;
                }
                function _contextSuffixLength() internal view virtual returns (uint256) {
                    return 0;
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[50] private __gap;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            

            File 6 of 7: PacayaForkRouter
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "./ForkRouter.sol";
            /// @title IOntakeFork
            /// @dev Derived from TaikoL1.sol in the Taiko Ontake fork
            /// https://github.com/taikoxyz/taiko-mono/releases/tag/protocol-v1.11.0
            /// @custom:security-contact [email protected]
            interface IOntakeFork {
                function proposeBlockV2(bytes calldata, bytes calldata) external;
                function proposeBlocksV2(bytes[] calldata, bytes[] calldata) external;
                function proveBlock(uint64, bytes calldata) external;
                function proveBlocks(uint64[] calldata, bytes[] calldata, bytes calldata) external;
                function verifyBlocks(uint64) external;
                function getVerifiedBlockProver(uint64) external view;
                function getLastVerifiedBlock() external view;
                function getBlockV2(uint64) external view;
                function getTransition(uint64, uint32) external view;
                function getTransition(uint64, bytes32) external;
                function getTransitions(uint64[] calldata, bytes32[] calldata) external;
                function lastProposedIn() external view;
                function getStateVariables() external view;
                function getConfig() external pure;
                function resolve(uint64, bytes32, bool) external view;
                function resolve(bytes32, bool) external view;
            }
            /// @title PacayaForkRouter
            /// @notice This contract routes calls to the current fork.
            /// @custom:security-contact [email protected]
            contract PacayaForkRouter is ForkRouter {
                constructor(address _oldFork, address _newFork) ForkRouter(_oldFork, _newFork) { }
                function shouldRouteToOldFork(bytes4 _selector) public pure override returns (bool) {
                    if (
                        _selector == IOntakeFork.proposeBlockV2.selector
                            || _selector == IOntakeFork.proposeBlocksV2.selector
                            || _selector == IOntakeFork.proveBlock.selector
                            || _selector == IOntakeFork.proveBlocks.selector
                            || _selector == IOntakeFork.verifyBlocks.selector
                            || _selector == IOntakeFork.getVerifiedBlockProver.selector
                            || _selector == IOntakeFork.getLastVerifiedBlock.selector
                            || _selector == IOntakeFork.getBlockV2.selector
                            || _selector == bytes4(keccak256("getTransition(uint64,uint32)"))
                            || _selector == bytes4(keccak256("getTransition(uint64,bytes32)"))
                            || _selector == IOntakeFork.getTransitions.selector
                            || _selector == IOntakeFork.lastProposedIn.selector
                            || _selector == IOntakeFork.getStateVariables.selector
                            || _selector == IOntakeFork.getConfig.selector
                            || _selector == bytes4(keccak256("resolve(uint64,bytes32,bool)"))
                            || _selector == bytes4(keccak256("resolve(bytes32,bool)"))
                    ) return true;
                    return false;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
            import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
            /// @title ForkRouter
            /// @custom:security-contact [email protected]
            /// @notice This contract routes calls to the current fork.
            ///
            ///                         +--> newFork
            /// PROXY -> FORK_ROUTER--|
            ///                         +--> oldFork
            contract ForkRouter is UUPSUpgradeable, Ownable2StepUpgradeable {
                address public immutable oldFork;
                address public immutable newFork;
                error InvalidParams();
                error ZeroForkAddress();
                constructor(address _oldFork, address _newFork) {
                    require(_newFork != address(0), InvalidParams());
                    require(_newFork != _oldFork, InvalidParams());
                    oldFork = _oldFork;
                    newFork = _newFork;
                    _disableInitializers();
                }
                fallback() external payable virtual {
                    _fallback();
                }
                receive() external payable virtual {
                    _fallback();
                }
                /// @notice Returns true if a function should be routed to the old fork
                /// @dev This function should be overridden by the implementation contract
                function shouldRouteToOldFork(bytes4) public pure virtual returns (bool) {
                    return false;
                }
                function _fallback() internal virtual {
                    address fork = shouldRouteToOldFork(msg.sig) ? oldFork : newFork;
                    require(fork != address(0), ZeroForkAddress());
                    assembly {
                        calldatacopy(0, 0, calldatasize())
                        let result := delegatecall(gas(), fork, 0, calldatasize(), 0, 0)
                        returndatacopy(0, 0, returndatasize())
                        switch result
                        case 0 { revert(0, returndatasize()) }
                        default { return(0, returndatasize()) }
                    }
                }
                function _authorizeUpgrade(address) internal virtual override onlyOwner { }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
            pragma solidity ^0.8.0;
            import "../../interfaces/draft-IERC1822.sol";
            import "../ERC1967/ERC1967Upgrade.sol";
            /**
             * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
             * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
             *
             * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
             * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
             * `UUPSUpgradeable` with a custom implementation of upgrades.
             *
             * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
             *
             * _Available since v4.1._
             */
            abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
                /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
                address private immutable __self = address(this);
                /**
                 * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
                 * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
                 * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
                 * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
                 * fail.
                 */
                modifier onlyProxy() {
                    require(address(this) != __self, "Function must be called through delegatecall");
                    require(_getImplementation() == __self, "Function must be called through active proxy");
                    _;
                }
                /**
                 * @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, "UUPSUpgradeable: must not be called through delegatecall");
                    _;
                }
                /**
                 * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
                 * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                 *
                 * 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. This is guaranteed by the `notDelegated` modifier.
                 */
                function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
                    return _IMPLEMENTATION_SLOT;
                }
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeTo(address newImplementation) public virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
                }
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                 * encoded in `data`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, data, true);
                }
                /**
                 * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                 * {upgradeTo} and {upgradeToAndCall}.
                 *
                 * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                 *
                 * ```solidity
                 * function _authorizeUpgrade(address) internal override onlyOwner {}
                 * ```
                 */
                function _authorizeUpgrade(address newImplementation) internal virtual;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
            pragma solidity ^0.8.0;
            import "./OwnableUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which provides access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership} and {acceptOwnership}.
             *
             * This module is used through inheritance. It will make available all functions
             * from parent (Ownable).
             */
            abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
                address private _pendingOwner;
                event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
                function __Ownable2Step_init() internal onlyInitializing {
                    __Ownable_init_unchained();
                }
                function __Ownable2Step_init_unchained() internal onlyInitializing {
                }
                /**
                 * @dev Returns the address of the pending owner.
                 */
                function pendingOwner() public view virtual returns (address) {
                    return _pendingOwner;
                }
                /**
                 * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual override onlyOwner {
                    _pendingOwner = newOwner;
                    emit OwnershipTransferStarted(owner(), newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual override {
                    delete _pendingOwner;
                    super._transferOwnership(newOwner);
                }
                /**
                 * @dev The new owner accepts the ownership transfer.
                 */
                function acceptOwnership() public virtual {
                    address sender = _msgSender();
                    require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
                    _transferOwnership(sender);
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[49] private __gap;
            }
            // 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.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
            pragma solidity ^0.8.2;
            import "../beacon/IBeacon.sol";
            import "../../interfaces/IERC1967.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._
             */
            abstract contract ERC1967Upgrade is IERC1967 {
                // 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 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 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 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 (last updated v4.9.0) (access/Ownable.sol)
            pragma solidity ^0.8.0;
            import "../utils/ContextUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
                address private _owner;
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                function __Ownable_init() internal onlyInitializing {
                    __Ownable_init_unchained();
                }
                function __Ownable_init_unchained() internal onlyInitializing {
                    _transferOwnership(_msgSender());
                }
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    _checkOwner();
                    _;
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    return _owner;
                }
                /**
                 * @dev Throws if the sender is not the owner.
                 */
                function _checkOwner() internal view virtual {
                    require(owner() == _msgSender(), "Ownable: caller is not the owner");
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby disabling any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    _transferOwnership(address(0));
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    require(newOwner != address(0), "Ownable: new owner is the zero address");
                    _transferOwnership(newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual {
                    address oldOwner = _owner;
                    _owner = newOwner;
                    emit OwnershipTransferred(oldOwner, newOwner);
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[49] private __gap;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
            pragma solidity ^0.8.2;
            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.
             *
             * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
             * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
             * case an upgrade adds a module that needs to be initialized.
             *
             * For example:
             *
             * [.hljs-theme-light.nopadding]
             * ```solidity
             * contract MyToken is ERC20Upgradeable {
             *     function initialize() initializer public {
             *         __ERC20_init("MyToken", "MTK");
             *     }
             * }
             *
             * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
             *     function initializeV2() reinitializer(2) public {
             *         __ERC20Permit_init("MyToken");
             *     }
             * }
             * ```
             *
             * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
             * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
             *
             * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
             * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
             *
             * [CAUTION]
             * ====
             * Avoid leaving a contract uninitialized.
             *
             * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
             * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
             * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
             *
             * [.hljs-theme-light.nopadding]
             * ```
             * /// @custom:oz-upgrades-unsafe-allow constructor
             * constructor() {
             *     _disableInitializers();
             * }
             * ```
             * ====
             */
            abstract contract Initializable {
                /**
                 * @dev Indicates that the contract has been initialized.
                 * @custom:oz-retyped-from bool
                 */
                uint8 private _initialized;
                /**
                 * @dev Indicates that the contract is in the process of being initialized.
                 */
                bool private _initializing;
                /**
                 * @dev Triggered when the contract has been initialized or reinitialized.
                 */
                event Initialized(uint8 version);
                /**
                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                 * `onlyInitializing` functions can be used to initialize parent contracts.
                 *
                 * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
                 * constructor.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier initializer() {
                    bool isTopLevelCall = !_initializing;
                    require(
                        (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                        "Initializable: contract is already initialized"
                    );
                    _initialized = 1;
                    if (isTopLevelCall) {
                        _initializing = true;
                    }
                    _;
                    if (isTopLevelCall) {
                        _initializing = false;
                        emit Initialized(1);
                    }
                }
                /**
                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                 * used to initialize parent contracts.
                 *
                 * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                 * are added through upgrades and that require initialization.
                 *
                 * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                 * cannot be nested. If one is invoked in the context of another, execution will revert.
                 *
                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                 * a contract, executing them in the right order is up to the developer or operator.
                 *
                 * WARNING: setting the version to 255 will prevent any future reinitialization.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier reinitializer(uint8 version) {
                    require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                    _initialized = version;
                    _initializing = true;
                    _;
                    _initializing = false;
                    emit Initialized(version);
                }
                /**
                 * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                 * {initializer} and {reinitializer} modifiers, directly or indirectly.
                 */
                modifier onlyInitializing() {
                    require(_initializing, "Initializable: contract is not initializing");
                    _;
                }
                /**
                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                 * through proxies.
                 *
                 * Emits an {Initialized} event the first time it is successfully executed.
                 */
                function _disableInitializers() internal virtual {
                    require(!_initializing, "Initializable: contract is initializing");
                    if (_initialized != type(uint8).max) {
                        _initialized = type(uint8).max;
                        emit Initialized(type(uint8).max);
                    }
                }
                /**
                 * @dev Returns the highest version that has been initialized. See {reinitializer}.
                 */
                function _getInitializedVersion() internal view returns (uint8) {
                    return _initialized;
                }
                /**
                 * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                 */
                function _isInitializing() internal view returns (bool) {
                    return _initializing;
                }
            }
            // 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.9.0) (interfaces/IERC1967.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
             *
             * _Available since v4.8.3._
             */
            interface IERC1967 {
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            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:
             * ```solidity
             * 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`, `uint256`._
             * _Available since v4.9 for `string`, `bytes`._
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes value;
                }
                /**
                 * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                 */
                function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                 */
                function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                 */
                function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                 */
                function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
            pragma solidity ^0.8.0;
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Provides information about the current execution context, including the
             * sender of the transaction and its data. While these are generally available
             * via msg.sender and msg.data, they should not be accessed in such a direct
             * manner, since when dealing with meta-transactions the account sending and
             * paying for execution may not be the actual sender (as far as an application
             * is concerned).
             *
             * This contract is only required for intermediate, library-like contracts.
             */
            abstract contract ContextUpgradeable is Initializable {
                function __Context_init() internal onlyInitializing {
                }
                function __Context_init_unchained() internal onlyInitializing {
                }
                function _msgSender() internal view virtual returns (address) {
                    return msg.sender;
                }
                function _msgData() internal view virtual returns (bytes calldata) {
                    return msg.data;
                }
                function _contextSuffixLength() internal view virtual returns (uint256) {
                    return 0;
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[50] private __gap;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            

            File 7 of 7: MainnetInbox
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "src/layer1/based/TaikoInbox.sol";
            import "src/shared/libs/LibNetwork.sol";
            import "./libs/LibFasterReentryLock.sol";
            /// @title MainnetTaikoL1
            /// @dev This contract shall be deployed to replace its parent contract on Ethereum for Taiko
            /// mainnet to reduce gas cost.
            /// @notice See the documentation in {TaikoL1}.
            /// @custom:security-contact [email protected]
            contract MainnetInbox is TaikoInbox {
                constructor(
                    address _wrapper,
                    address _verifier,
                    address _bondToken,
                    address _signalService
                )
                    TaikoInbox(_wrapper, _verifier, _bondToken, _signalService)
                { }
                function pacayaConfig() public pure override returns (ITaikoInbox.Config memory) {
                    // All hard-coded configurations:
                    // - treasury: the actual TaikoL2 address.
                    // - anchorGasLimit: 1_000_000
                    return ITaikoInbox.Config({
                        chainId: LibNetwork.TAIKO_MAINNET,
                        // Ring buffers are being reused on the mainnet, therefore the following two
                        // configuration values must NEVER be changed!!!
                        maxUnverifiedBatches: 324_000, // DO NOT CHANGE!!!
                        batchRingBufferSize: 360_000, // DO NOT CHANGE!!!
                        maxBatchesToVerify: 16,
                        blockMaxGasLimit: 240_000_000,
                        livenessBondBase: 125e18, // 125 Taiko token per batch
                        livenessBondPerBlock: 0, // deprecated
                        stateRootSyncInternal: 4,
                        maxAnchorHeightOffset: 64,
                        baseFeeConfig: LibSharedData.BaseFeeConfig({
                            adjustmentQuotient: 8,
                            sharingPctg: 50,
                            gasIssuancePerSecond: 5_000_000,
                            minGasExcess: 1_344_899_430, // 0.01 gwei
                            maxGasIssuancePerBlock: 600_000_000 // two minutes: 5_000_000 * 120
                         }),
                        provingWindow: 2 hours,
                        cooldownWindow: 2 hours,
                        maxSignalsToReceive: 16,
                        maxBlocksPerBatch: 768,
                        forkHeights: ITaikoInbox.ForkHeights({
                            ontake: 538_304,
                            pacaya: 1_166_000,
                            shasta: 0,
                            unzen: 0
                        })
                    });
                }
                function _storeReentryLock(uint8 _reentry) internal override {
                    LibFasterReentryLock.storeReentryLock(_reentry);
                }
                function _loadReentryLock() internal view override returns (uint8) {
                    return LibFasterReentryLock.loadReentryLock();
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
            import "src/shared/common/EssentialContract.sol";
            import "src/shared/based/ITaiko.sol";
            import "src/shared/libs/LibAddress.sol";
            import "src/shared/libs/LibMath.sol";
            import "src/shared/libs/LibNetwork.sol";
            import "src/shared/libs/LibStrings.sol";
            import "src/shared/signal/ISignalService.sol";
            import "src/layer1/verifiers/IVerifier.sol";
            import "./ITaikoInbox.sol";
            import "./IProposeBatch.sol";
            /// @title TaikoInbox
            /// @notice Acts as the inbox for the Taiko Alethia protocol, a simplified version of the
            /// original Taiko-Based Contestable Rollup (BCR). The tier-based proof system and
            /// contestation mechanisms have been removed.
            ///
            /// Key assumptions of this protocol:
            /// - Block proposals and proofs are asynchronous. Proofs are not available at proposal time,
            ///   unlike Taiko Gwyneth, which assumes synchronous composability.
            /// - Proofs are presumed error-free and thoroughly validated, with subproofs/multiproofs management
            /// delegated to IVerifier contracts.
            ///
            /// @dev Registered in the address resolver as "taiko".
            /// @custom:security-contact [email protected]
            abstract contract TaikoInbox is EssentialContract, ITaikoInbox, IProposeBatch, ITaiko {
                using LibMath for uint256;
                using SafeERC20 for IERC20;
                address public immutable inboxWrapper;
                address public immutable verifier;
                address public immutable bondToken;
                ISignalService public immutable signalService;
                State public state; // storage layout much match Ontake fork
                uint256[50] private __gap;
                // External functions ------------------------------------------------------------------------
                constructor(
                    address _inboxWrapper,
                    address _verifier,
                    address _bondToken,
                    address _signalService
                )
                    nonZeroAddr(_verifier)
                    nonZeroAddr(_signalService)
                    EssentialContract(address(0))
                {
                    inboxWrapper = _inboxWrapper;
                    verifier = _verifier;
                    bondToken = _bondToken;
                    signalService = ISignalService(_signalService);
                }
                function init(address _owner, bytes32 _genesisBlockHash) external initializer {
                    __Taiko_init(_owner, _genesisBlockHash);
                }
                /// @notice Proposes a batch of blocks.
                /// @param _params ABI-encoded BlockParams.
                /// @param _txList Transaction list in calldata. If the txList is empty, blob will be used for
                /// data availability.
                /// @return info_ Information of the proposed batch, which is used for constructing blocks
                /// offchain.
                /// @return meta_ Metadata of the proposed batch, which is used for proving the batch.
                function proposeBatch(
                    bytes calldata _params,
                    bytes calldata _txList
                )
                    public
                    override(ITaikoInbox, IProposeBatch)
                    nonReentrant
                    returns (BatchInfo memory info_, BatchMetadata memory meta_)
                {
                    Stats2 memory stats2 = state.stats2;
                    Config memory config = pacayaConfig();
                    require(stats2.numBatches >= config.forkHeights.pacaya, ForkNotActivated());
                    unchecked {
                        require(
                            stats2.numBatches <= stats2.lastVerifiedBatchId + config.maxUnverifiedBatches,
                            TooManyBatches()
                        );
                        BatchParams memory params = abi.decode(_params, (BatchParams));
                        {
                            if (inboxWrapper == address(0)) {
                                require(params.proposer == address(0), CustomProposerNotAllowed());
                                params.proposer = msg.sender;
                                // blob hashes are only accepted if the caller is trusted.
                                require(params.blobParams.blobHashes.length == 0, InvalidBlobParams());
                                require(params.blobParams.createdIn == 0, InvalidBlobCreatedIn());
                            } else {
                                require(params.proposer != address(0), CustomProposerMissing());
                                require(msg.sender == inboxWrapper, NotInboxWrapper());
                            }
                            // In the upcoming Shasta fork, we might need to enforce the coinbase address as the
                            // preconfer address. This will allow us to implement preconfirmation features in L2
                            // anchor transactions.
                            if (params.coinbase == address(0)) {
                                params.coinbase = params.proposer;
                            }
                            if (params.revertIfNotFirstProposal) {
                                require(state.stats2.lastProposedIn != block.number, NotFirstProposal());
                            }
                        }
                        bool calldataUsed = _txList.length != 0;
                        if (calldataUsed) {
                            // calldata is used for data availability
                            require(params.blobParams.firstBlobIndex == 0, InvalidBlobParams());
                            require(params.blobParams.numBlobs == 0, InvalidBlobParams());
                            require(params.blobParams.createdIn == 0, InvalidBlobCreatedIn());
                            require(params.blobParams.blobHashes.length == 0, InvalidBlobParams());
                        } else if (params.blobParams.blobHashes.length == 0) {
                            // this is a normal batch, blobs are created and used in the current batches.
                            // firstBlobIndex can be non-zero.
                            require(params.blobParams.numBlobs != 0, BlobNotSpecified());
                            require(params.blobParams.createdIn == 0, InvalidBlobCreatedIn());
                            params.blobParams.createdIn = uint64(block.number);
                        } else {
                            // this is a forced-inclusion batch, blobs were created in early blocks and are used
                            // in the current batches
                            require(params.blobParams.createdIn != 0, InvalidBlobCreatedIn());
                            require(params.blobParams.numBlobs == 0, InvalidBlobParams());
                            require(params.blobParams.firstBlobIndex == 0, InvalidBlobParams());
                        }
                        // Keep track of last batch's information.
                        Batch storage lastBatch =
                            state.batches[(stats2.numBatches - 1) % config.batchRingBufferSize];
                        (uint64 anchorBlockId, uint64 lastBlockTimestamp) = _validateBatchParams(
                            params,
                            config.maxAnchorHeightOffset,
                            config.maxSignalsToReceive,
                            config.maxBlocksPerBatch,
                            lastBatch
                        );
                        // This section constructs the metadata for the proposed batch, which is crucial for
                        // nodes/clients to process the batch. The metadata itself is not stored on-chain;
                        // instead, only its hash is kept.
                        // The metadata must be supplied as calldata prior to proving the batch, enabling the
                        // computation and verification of its integrity through the comparison of the metahash.
                        //
                        // Note that `difficulty` has been removed from the metadata. The client and prover must
                        // use
                        // the following approach to calculate a block's difficulty:
                        //  `keccak256(abi.encode("TAIKO_DIFFICULTY", block.number))`
                        info_ = BatchInfo({
                            txsHash: bytes32(0), // to be initialised later
                            //
                            // Data to build L2 blocks
                            blocks: params.blocks,
                            blobHashes: new bytes32[](0), // to be initialised later
                            extraData: bytes32(uint256(config.baseFeeConfig.sharingPctg)),
                            coinbase: params.coinbase,
                            proposedIn: uint64(block.number),
                            blobCreatedIn: params.blobParams.createdIn,
                            blobByteOffset: params.blobParams.byteOffset,
                            blobByteSize: params.blobParams.byteSize,
                            gasLimit: config.blockMaxGasLimit,
                            lastBlockId: 0, // to be initialised later
                            lastBlockTimestamp: lastBlockTimestamp,
                            //
                            // Data for the L2 anchor transaction, shared by all blocks in the batch
                            anchorBlockId: anchorBlockId,
                            anchorBlockHash: blockhash(anchorBlockId),
                            baseFeeConfig: config.baseFeeConfig
                        });
                        require(info_.anchorBlockHash != 0, ZeroAnchorBlockHash());
                        info_.lastBlockId = stats2.numBatches == config.forkHeights.pacaya
                            ? stats2.numBatches + uint64(params.blocks.length) - 1
                            : lastBatch.lastBlockId + uint64(params.blocks.length);
                        (info_.txsHash, info_.blobHashes) =
                            _calculateTxsHash(keccak256(_txList), params.blobParams);
                        meta_ = BatchMetadata({
                            infoHash: keccak256(abi.encode(info_)),
                            proposer: params.proposer,
                            batchId: stats2.numBatches,
                            proposedAt: uint64(block.timestamp)
                        });
                        Batch storage batch = state.batches[stats2.numBatches % config.batchRingBufferSize];
                        // SSTORE #1
                        batch.metaHash = keccak256(abi.encode(meta_));
                        // SSTORE #2 {{
                        batch.batchId = stats2.numBatches;
                        batch.lastBlockTimestamp = lastBlockTimestamp;
                        batch.anchorBlockId = anchorBlockId;
                        batch.nextTransitionId = 1;
                        batch.verifiedTransitionId = 0;
                        batch.reserved4 = 0;
                        // SSTORE }}
                        _debitBond(params.proposer, config.livenessBondBase);
                        // SSTORE #3 {{
                        batch.lastBlockId = info_.lastBlockId;
                        batch.reserved3 = 0;
                        batch.livenessBond = config.livenessBondBase;
                        // SSTORE }}
                        stats2.numBatches += 1;
                        require(
                            config.forkHeights.shasta == 0 || stats2.numBatches < config.forkHeights.shasta,
                            BeyondCurrentFork()
                        );
                        stats2.lastProposedIn = uint56(block.number);
                        emit BatchProposed(info_, meta_, _txList);
                    } // end-of-unchecked
                    _verifyBatches(config, stats2, 1);
                }
                /// @notice Proves multiple batches with a single aggregated proof.
                /// @param _params ABI-encoded parameter containing:
                /// - metas: Array of metadata for each batch being proved.
                /// - transitions: Array of batch transitions to be proved.
                /// @param _proof The aggregated cryptographic proof proving the batches transitions.
                function proveBatches(bytes calldata _params, bytes calldata _proof) external nonReentrant {
                    (BatchMetadata[] memory metas, Transition[] memory trans) =
                        abi.decode(_params, (BatchMetadata[], Transition[]));
                    uint256 metasLength = metas.length;
                    require(metasLength != 0, NoBlocksToProve());
                    require(metasLength == trans.length, ArraySizesMismatch());
                    Stats2 memory stats2 = state.stats2;
                    require(!stats2.paused, ContractPaused());
                    Config memory config = pacayaConfig();
                    IVerifier.Context[] memory ctxs = new IVerifier.Context[](metasLength);
                    bool hasConflictingProof;
                    for (uint256 i; i < metasLength; ++i) {
                        BatchMetadata memory meta = metas[i];
                        require(meta.batchId >= config.forkHeights.pacaya, ForkNotActivated());
                        require(
                            config.forkHeights.shasta == 0 || meta.batchId < config.forkHeights.shasta,
                            BeyondCurrentFork()
                        );
                        require(meta.batchId > stats2.lastVerifiedBatchId, BatchNotFound());
                        require(meta.batchId < stats2.numBatches, BatchNotFound());
                        Transition memory tran = trans[i];
                        require(tran.parentHash != 0, InvalidTransitionParentHash());
                        require(tran.blockHash != 0, InvalidTransitionBlockHash());
                        require(tran.stateRoot != 0, InvalidTransitionStateRoot());
                        ctxs[i].batchId = meta.batchId;
                        ctxs[i].metaHash = keccak256(abi.encode(meta));
                        ctxs[i].transition = tran;
                        // Verify the batch's metadata.
                        uint256 slot = meta.batchId % config.batchRingBufferSize;
                        Batch storage batch = state.batches[slot];
                        require(ctxs[i].metaHash == batch.metaHash, MetaHashMismatch());
                        // Finds out if this transition is overwriting an existing one (with the same parent
                        // hash) or is a new one.
                        uint24 tid;
                        uint24 nextTransitionId = batch.nextTransitionId;
                        if (nextTransitionId > 1) {
                            // This batch has at least one transition.
                            if (state.transitions[slot][1].parentHash == tran.parentHash) {
                                // Overwrite the first transition.
                                tid = 1;
                            } else if (nextTransitionId > 2) {
                                // Retrieve the transition ID using the parent hash from the mapping. If the ID
                                // is 0, it indicates a new transition; otherwise, it's an overwrite of an
                                // existing transition.
                                tid = state.transitionIds[meta.batchId][tran.parentHash];
                            }
                        }
                        if (tid == 0) {
                            // This transition is new, we need to use the next available ID.
                            unchecked {
                                tid = batch.nextTransitionId++;
                            }
                        } else {
                            TransitionState memory _ts = state.transitions[slot][tid];
                            if (_ts.blockHash == 0) {
                                // This transition has been invalidated due to a conflicting proof.
                                // So we can reuse the transition ID.
                            } else {
                                bool isSameTransition = _ts.blockHash == tran.blockHash
                                    && (_ts.stateRoot == 0 || _ts.stateRoot == tran.stateRoot);
                                if (isSameTransition) {
                                    // Re-approving the same transition is allowed, but we will not change the
                                    // existing one.
                                } else {
                                    // A conflict is detected with the new transition. Pause the contract and
                                    // invalidate the existing transition by setting its blockHash to 0.
                                    hasConflictingProof = true;
                                    state.transitions[slot][tid].blockHash = 0;
                                    emit ConflictingProof(meta.batchId, _ts, tran);
                                }
                                // Proceed with other transitions.
                                continue;
                            }
                        }
                        TransitionState storage ts = state.transitions[slot][tid];
                        ts.blockHash = tran.blockHash;
                        ts.stateRoot =
                            meta.batchId % config.stateRootSyncInternal == 0 ? tran.stateRoot : bytes32(0);
                        bool inProvingWindow;
                        unchecked {
                            inProvingWindow = block.timestamp
                                <= uint256(meta.proposedAt).max(stats2.lastUnpausedAt) + config.provingWindow;
                        }
                        ts.inProvingWindow = inProvingWindow;
                        ts.prover = inProvingWindow ? meta.proposer : msg.sender;
                        ts.createdAt = uint48(block.timestamp);
                        if (tid == 1) {
                            ts.parentHash = tran.parentHash;
                        } else {
                            state.transitionIds[meta.batchId][tran.parentHash] = tid;
                        }
                    }
                    IVerifier(verifier).verifyProof(ctxs, _proof);
                    // Emit the event
                    {
                        uint64[] memory batchIds = new uint64[](metasLength);
                        for (uint256 i; i < metasLength; ++i) {
                            batchIds[i] = metas[i].batchId;
                        }
                        emit BatchesProved(verifier, batchIds, trans);
                    }
                    if (hasConflictingProof) {
                        _pause();
                        emit Paused(verifier);
                    } else {
                        _verifyBatches(config, stats2, metasLength);
                    }
                }
                /// @notice Verify batches by providing the length of the batches to verify.
                /// @dev This function is necessary to upgrade from this fork to the next one.
                /// @param _length Specifis how many batches to verify. The max number of batches to verify is
                /// `pacayaConfig().maxBatchesToVerify * _length`.
                function verifyBatches(uint64 _length)
                    external
                    nonZeroValue(_length)
                    nonReentrant
                    whenNotPaused
                {
                    _verifyBatches(pacayaConfig(), state.stats2, _length);
                }
                /// @inheritdoc ITaikoInbox
                function depositBond(uint256 _amount) external payable whenNotPaused {
                    state.bondBalance[msg.sender] += _handleDeposit(msg.sender, _amount);
                }
                /// @inheritdoc ITaikoInbox
                function withdrawBond(uint256 _amount) external whenNotPaused {
                    uint256 balance = state.bondBalance[msg.sender];
                    require(balance >= _amount, InsufficientBond());
                    emit BondWithdrawn(msg.sender, _amount);
                    state.bondBalance[msg.sender] -= _amount;
                    if (bondToken != address(0)) {
                        IERC20(bondToken).safeTransfer(msg.sender, _amount);
                    } else {
                        LibAddress.sendEtherAndVerify(msg.sender, _amount);
                    }
                }
                /// @inheritdoc ITaikoInbox
                function getStats1() external view returns (Stats1 memory) {
                    return state.stats1;
                }
                /// @inheritdoc ITaikoInbox
                function getStats2() external view returns (Stats2 memory) {
                    return state.stats2;
                }
                /// @inheritdoc ITaikoInbox
                function getTransitionById(
                    uint64 _batchId,
                    uint24 _tid
                )
                    external
                    view
                    returns (TransitionState memory)
                {
                    Config memory config = pacayaConfig();
                    uint256 slot = _batchId % config.batchRingBufferSize;
                    Batch storage batch = state.batches[slot];
                    require(batch.batchId == _batchId, BatchNotFound());
                    require(_tid != 0, TransitionNotFound());
                    require(_tid < batch.nextTransitionId, TransitionNotFound());
                    return state.transitions[slot][_tid];
                }
                /// @inheritdoc ITaikoInbox
                function getTransitionByParentHash(
                    uint64 _batchId,
                    bytes32 _parentHash
                )
                    external
                    view
                    returns (TransitionState memory)
                {
                    Config memory config = pacayaConfig();
                    uint256 slot = _batchId % config.batchRingBufferSize;
                    Batch storage batch = state.batches[slot];
                    require(batch.batchId == _batchId, BatchNotFound());
                    uint24 tid;
                    if (batch.nextTransitionId > 1) {
                        // This batch has at least one transition.
                        if (state.transitions[slot][1].parentHash == _parentHash) {
                            // Overwrite the first transition.
                            tid = 1;
                        } else if (batch.nextTransitionId > 2) {
                            // Retrieve the transition ID using the parent hash from the mapping. If the ID
                            // is 0, it indicates a new transition; otherwise, it's an overwrite of an
                            // existing transition.
                            tid = state.transitionIds[_batchId][_parentHash];
                        }
                    }
                    require(tid != 0 && tid < batch.nextTransitionId, TransitionNotFound());
                    return state.transitions[slot][tid];
                }
                /// @inheritdoc ITaikoInbox
                function getLastVerifiedTransition()
                    external
                    view
                    returns (uint64 batchId_, uint64 blockId_, TransitionState memory ts_)
                {
                    batchId_ = state.stats2.lastVerifiedBatchId;
                    require(batchId_ >= pacayaConfig().forkHeights.pacaya, BatchNotFound());
                    blockId_ = getBatch(batchId_).lastBlockId;
                    ts_ = getBatchVerifyingTransition(batchId_);
                }
                /// @inheritdoc ITaikoInbox
                function getLastSyncedTransition()
                    external
                    view
                    returns (uint64 batchId_, uint64 blockId_, TransitionState memory ts_)
                {
                    batchId_ = state.stats1.lastSyncedBatchId;
                    blockId_ = getBatch(batchId_).lastBlockId;
                    ts_ = getBatchVerifyingTransition(batchId_);
                }
                /// @inheritdoc ITaikoInbox
                function bondBalanceOf(address _user) external view returns (uint256) {
                    return state.bondBalance[_user];
                }
                /// @notice Determines the operational layer of the contract, whether it is on Layer 1 (L1) or
                /// Layer 2 (L2).
                /// @return True if the contract is operating on L1, false if on L2.
                function isOnL1() external pure override returns (bool) {
                    return true;
                }
                // Public functions -------------------------------------------------------------------------
                /// @inheritdoc EssentialContract
                function paused() public view override returns (bool) {
                    return state.stats2.paused;
                }
                /// @inheritdoc ITaikoInbox
                function getBatch(uint64 _batchId) public view returns (Batch memory batch_) {
                    Config memory config = pacayaConfig();
                    batch_ = state.batches[_batchId % config.batchRingBufferSize];
                    require(batch_.batchId == _batchId, BatchNotFound());
                }
                /// @inheritdoc ITaikoInbox
                function getBatchVerifyingTransition(uint64 _batchId)
                    public
                    view
                    returns (TransitionState memory ts_)
                {
                    Config memory config = pacayaConfig();
                    uint64 slot = _batchId % config.batchRingBufferSize;
                    Batch storage batch = state.batches[slot];
                    require(batch.batchId == _batchId, BatchNotFound());
                    if (batch.verifiedTransitionId != 0) {
                        ts_ = state.transitions[slot][batch.verifiedTransitionId];
                    }
                }
                /// @inheritdoc ITaikoInbox
                function pacayaConfig() public view virtual returns (Config memory);
                // Internal functions ----------------------------------------------------------------------
                function __Taiko_init(address _owner, bytes32 _genesisBlockHash) internal onlyInitializing {
                    __Essential_init(_owner);
                    require(_genesisBlockHash != 0, InvalidGenesisBlockHash());
                    state.transitions[0][1].blockHash = _genesisBlockHash;
                    Batch storage batch = state.batches[0];
                    batch.metaHash = bytes32(uint256(1));
                    batch.lastBlockTimestamp = uint64(block.timestamp);
                    batch.anchorBlockId = uint64(block.number);
                    batch.nextTransitionId = 2;
                    batch.verifiedTransitionId = 1;
                    state.stats1.genesisHeight = uint64(block.number);
                    state.stats2.lastProposedIn = uint56(block.number);
                    state.stats2.numBatches = 1;
                    emit BatchesVerified(0, _genesisBlockHash);
                }
                function _unpause() internal override {
                    state.stats2.lastUnpausedAt = uint64(block.timestamp);
                    state.stats2.paused = false;
                }
                function _pause() internal override {
                    state.stats2.paused = true;
                }
                function _calculateTxsHash(
                    bytes32 _txListHash,
                    BlobParams memory _blobParams
                )
                    internal
                    view
                    virtual
                    returns (bytes32 hash_, bytes32[] memory blobHashes_)
                {
                    if (_blobParams.blobHashes.length != 0) {
                        blobHashes_ = _blobParams.blobHashes;
                    } else {
                        uint256 numBlobs = _blobParams.numBlobs;
                        blobHashes_ = new bytes32[](numBlobs);
                        for (uint256 i; i < numBlobs; ++i) {
                            unchecked {
                                blobHashes_[i] = blobhash(_blobParams.firstBlobIndex + i);
                            }
                        }
                    }
                    uint256 bloblHashesLength = blobHashes_.length;
                    for (uint256 i; i < bloblHashesLength; ++i) {
                        require(blobHashes_[i] != 0, BlobNotFound());
                    }
                    hash_ = keccak256(abi.encode(_txListHash, blobHashes_));
                }
                // Private functions -----------------------------------------------------------------------
                function _verifyBatches(
                    Config memory _config,
                    Stats2 memory _stats2,
                    uint256 _length
                )
                    private
                {
                    uint64 batchId = _stats2.lastVerifiedBatchId;
                    bool canVerifyBlocks;
                    unchecked {
                        uint64 pacayaForkHeight = _config.forkHeights.pacaya;
                        canVerifyBlocks = pacayaForkHeight == 0 || batchId >= pacayaForkHeight - 1;
                    }
                    if (canVerifyBlocks) {
                        uint256 slot = batchId % _config.batchRingBufferSize;
                        Batch storage batch = state.batches[slot];
                        uint24 tid = batch.verifiedTransitionId;
                        bytes32 blockHash = state.transitions[slot][tid].blockHash;
                        SyncBlock memory synced;
                        uint256 stopBatchId;
                        unchecked {
                            stopBatchId = (
                                _config.maxBatchesToVerify * _length + _stats2.lastVerifiedBatchId + 1
                            ).min(_stats2.numBatches);
                            if (_config.forkHeights.shasta != 0) {
                                stopBatchId = stopBatchId.min(_config.forkHeights.shasta);
                            }
                        }
                        for (++batchId; batchId < stopBatchId; ++batchId) {
                            slot = batchId % _config.batchRingBufferSize;
                            batch = state.batches[slot];
                            uint24 nextTransitionId = batch.nextTransitionId;
                            if (paused()) break;
                            if (nextTransitionId <= 1) break;
                            TransitionState storage ts = state.transitions[slot][1];
                            if (ts.parentHash == blockHash) {
                                tid = 1;
                            } else if (nextTransitionId > 2) {
                                uint24 _tid = state.transitionIds[batchId][blockHash];
                                if (_tid == 0) break;
                                tid = _tid;
                                ts = state.transitions[slot][tid];
                            } else {
                                break;
                            }
                            bytes32 _blockHash = ts.blockHash;
                            // This transition has been invalidated due to conflicting proof
                            if (_blockHash == 0) break;
                            unchecked {
                                if (ts.createdAt + _config.cooldownWindow > block.timestamp) {
                                    break;
                                }
                            }
                            blockHash = _blockHash;
                            uint96 bondToReturn =
                                ts.inProvingWindow ? batch.livenessBond : batch.livenessBond / 2;
                            _creditBond(ts.prover, bondToReturn);
                            if (batchId % _config.stateRootSyncInternal == 0) {
                                synced.batchId = batchId;
                                synced.blockId = batch.lastBlockId;
                                synced.tid = tid;
                                synced.stateRoot = ts.stateRoot;
                            }
                        }
                        unchecked {
                            --batchId;
                        }
                        if (_stats2.lastVerifiedBatchId != batchId) {
                            _stats2.lastVerifiedBatchId = batchId;
                            batch = state.batches[_stats2.lastVerifiedBatchId % _config.batchRingBufferSize];
                            batch.verifiedTransitionId = tid;
                            emit BatchesVerified(_stats2.lastVerifiedBatchId, blockHash);
                            if (synced.batchId != 0) {
                                if (synced.batchId != _stats2.lastVerifiedBatchId) {
                                    // We write the synced batch's verifiedTransitionId to storage
                                    batch = state.batches[synced.batchId % _config.batchRingBufferSize];
                                    batch.verifiedTransitionId = synced.tid;
                                }
                                Stats1 memory stats1 = state.stats1;
                                stats1.lastSyncedBatchId = batch.batchId;
                                stats1.lastSyncedAt = uint64(block.timestamp);
                                state.stats1 = stats1;
                                emit Stats1Updated(stats1);
                                // Ask signal service to write cross chain signal
                                signalService.syncChainData(
                                    _config.chainId, LibStrings.H_STATE_ROOT, synced.blockId, synced.stateRoot
                                );
                            }
                        }
                    }
                    state.stats2 = _stats2;
                    emit Stats2Updated(_stats2);
                }
                function _debitBond(address _user, uint256 _amount) private {
                    if (_amount == 0) return;
                    uint256 balance = state.bondBalance[_user];
                    if (balance >= _amount) {
                        unchecked {
                            state.bondBalance[_user] = balance - _amount;
                        }
                    } else if (bondToken != address(0)) {
                        uint256 amountDeposited = _handleDeposit(_user, _amount);
                        require(amountDeposited == _amount, InsufficientBond());
                    } else {
                        // Ether as bond must be deposited before proposing a batch
                        revert InsufficientBond();
                    }
                    emit BondDebited(_user, _amount);
                }
                function _creditBond(address _user, uint256 _amount) private {
                    if (_amount == 0) return;
                    unchecked {
                        state.bondBalance[_user] += _amount;
                    }
                    emit BondCredited(_user, _amount);
                }
                function _handleDeposit(
                    address _user,
                    uint256 _amount
                )
                    private
                    returns (uint256 amountDeposited_)
                {
                    if (bondToken != address(0)) {
                        require(msg.value == 0, MsgValueNotZero());
                        uint256 balance = IERC20(bondToken).balanceOf(address(this));
                        IERC20(bondToken).safeTransferFrom(_user, address(this), _amount);
                        amountDeposited_ = IERC20(bondToken).balanceOf(address(this)) - balance;
                    } else {
                        require(msg.value == _amount, EtherNotPaidAsBond());
                        amountDeposited_ = _amount;
                    }
                    emit BondDeposited(_user, amountDeposited_);
                }
                function _validateBatchParams(
                    BatchParams memory _params,
                    uint64 _maxAnchorHeightOffset,
                    uint8 _maxSignalsToReceive,
                    uint16 _maxBlocksPerBatch,
                    Batch memory _lastBatch
                )
                    private
                    view
                    returns (uint64 anchorBlockId_, uint64 lastBlockTimestamp_)
                {
                    uint256 blocksLength = _params.blocks.length;
                    require(blocksLength != 0, BlockNotFound());
                    require(blocksLength <= _maxBlocksPerBatch, TooManyBlocks());
                    unchecked {
                        if (_params.anchorBlockId == 0) {
                            anchorBlockId_ = uint64(block.number - 1);
                        } else {
                            require(
                                _params.anchorBlockId + _maxAnchorHeightOffset >= block.number,
                                AnchorBlockIdTooSmall()
                            );
                            require(_params.anchorBlockId < block.number, AnchorBlockIdTooLarge());
                            require(
                                _params.anchorBlockId >= _lastBatch.anchorBlockId,
                                AnchorBlockIdSmallerThanParent()
                            );
                            anchorBlockId_ = _params.anchorBlockId;
                        }
                        lastBlockTimestamp_ = _params.lastBlockTimestamp == 0
                            ? uint64(block.timestamp)
                            : _params.lastBlockTimestamp;
                        require(lastBlockTimestamp_ <= block.timestamp, TimestampTooLarge());
                        require(_params.blocks[0].timeShift == 0, FirstBlockTimeShiftNotZero());
                        uint64 totalShift;
                        for (uint256 i; i < blocksLength; ++i) {
                            totalShift += _params.blocks[i].timeShift;
                            uint256 numSignals = _params.blocks[i].signalSlots.length;
                            if (numSignals == 0) continue;
                            require(numSignals <= _maxSignalsToReceive, TooManySignals());
                            for (uint256 j; j < numSignals; ++j) {
                                require(
                                    signalService.isSignalSent(_params.blocks[i].signalSlots[j]),
                                    SignalNotSent()
                                );
                            }
                        }
                        require(lastBlockTimestamp_ >= totalShift, TimestampTooSmall());
                        uint64 firstBlockTimestamp = lastBlockTimestamp_ - totalShift;
                        require(
                            firstBlockTimestamp + _maxAnchorHeightOffset * LibNetwork.ETHEREUM_BLOCK_TIME
                                >= block.timestamp,
                            TimestampTooSmall()
                        );
                        require(
                            firstBlockTimestamp >= _lastBatch.lastBlockTimestamp, TimestampSmallerThanParent()
                        );
                        // make sure the batch builds on the expected latest chain state.
                        require(
                            _params.parentMetaHash == 0 || _params.parentMetaHash == _lastBatch.metaHash,
                            ParentMetaHashMismatch()
                        );
                    }
                }
                // Memory-only structs ----------------------------------------------------------------------
                struct SyncBlock {
                    uint64 batchId;
                    uint64 blockId;
                    uint24 tid;
                    bytes32 stateRoot;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title LibNetwork
            library LibNetwork {
                uint256 internal constant ETHEREUM_MAINNET = 1;
                uint256 internal constant ETHEREUM_ROPSTEN = 2;
                uint256 internal constant ETHEREUM_RINKEBY = 4;
                uint256 internal constant ETHEREUM_GOERLI = 5;
                uint256 internal constant ETHEREUM_KOVAN = 42;
                uint256 internal constant ETHEREUM_HOLESKY = 17_000;
                uint256 internal constant ETHEREUM_SEPOLIA = 11_155_111;
                uint256 internal constant ETHEREUM_HELDER = 7_014_190_335;
                uint256 internal constant ETHEREUM_HOODI = 560_048;
                uint64 internal constant TAIKO_MAINNET = 167_000;
                uint64 internal constant TAIKO_HEKLA = 167_009;
                uint64 internal constant TAIKO_DEVNET = 167_001;
                uint64 internal constant TAIKO_PRECONF = 167_010;
                uint256 internal constant ETHEREUM_BLOCK_TIME = 12 seconds;
                /// @dev Checks if the chain ID represents an Ethereum testnet.
                /// @param _chainId The chain ID.
                /// @return true if the chain ID represents an Ethereum testnet, false otherwise.
                function isEthereumTestnet(uint256 _chainId) internal pure returns (bool) {
                    return _chainId == LibNetwork.ETHEREUM_ROPSTEN || _chainId == LibNetwork.ETHEREUM_RINKEBY
                        || _chainId == LibNetwork.ETHEREUM_GOERLI || _chainId == LibNetwork.ETHEREUM_KOVAN
                        || _chainId == LibNetwork.ETHEREUM_HOLESKY || _chainId == LibNetwork.ETHEREUM_SEPOLIA
                        || _chainId == LibNetwork.ETHEREUM_HELDER || _chainId == LibNetwork.ETHEREUM_HOODI;
                }
                /// @dev Checks if the chain ID represents an Ethereum testnet or the Etheruem mainnet.
                /// @param _chainId The chain ID.
                /// @return true if the chain ID represents an Ethereum testnet or the Etheruem mainnet, false
                /// otherwise.
                function isEthereumMainnetOrTestnet(uint256 _chainId) internal pure returns (bool) {
                    return _chainId == LibNetwork.ETHEREUM_MAINNET || isEthereumTestnet(_chainId);
                }
                /// @dev Checks if the chain ID represents the Taiko L2 mainnet.
                /// @param _chainId The chain ID.
                /// @return true if the chain ID represents the Taiko L2 mainnet.
                function isTaikoMainnet(uint256 _chainId) internal pure returns (bool) {
                    return _chainId == TAIKO_MAINNET;
                }
                /// @dev Checks if the chain ID represents an internal Taiko devnet's base layer.
                /// @param _chainId The chain ID.
                /// @return true if the chain ID represents an internal Taiko devnet's base layer, false
                /// otherwise.
                function isTaikoDevnet(uint256 _chainId) internal pure returns (bool) {
                    return _chainId >= 32_300 && _chainId <= 32_400;
                }
                /// @dev Checks if the chain supports Dencun hardfork. Note that this check doesn't need to be
                /// exhaustive.
                /// @param _chainId The chain ID.
                /// @return true if the chain supports Dencun hardfork, false otherwise.
                function isDencunSupported(uint256 _chainId) internal pure returns (bool) {
                    return _chainId == LibNetwork.ETHEREUM_MAINNET || _chainId == LibNetwork.ETHEREUM_HOLESKY
                        || _chainId == LibNetwork.ETHEREUM_SEPOLIA || _chainId == LibNetwork.ETHEREUM_HELDER
                        || _chainId == LibNetwork.ETHEREUM_HOODI || isTaikoDevnet(_chainId);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title LibFasterReentryLock
            /// @custom:security-contact [email protected]
            library LibFasterReentryLock {
                /// @dev The slot in transient storage of the reentry lock.
                /// This is the result of keccak256("ownerUUPS.reentry_slot") plus 1. The addition aims to
                /// prevent hash collisions with slots defined in EIP-1967, where slots are derived by
                /// keccak256("something") - 1, and with slots in SignalService, calculated directly with
                /// keccak256("something").
                bytes32 private constant _REENTRY_SLOT =
                    0xa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721b;
                function storeReentryLock(uint8 _reentry) internal {
                    assembly {
                        tstore(_REENTRY_SLOT, _reentry)
                    }
                }
                function loadReentryLock() internal view returns (uint8 reentry_) {
                    assembly {
                        reentry_ := tload(_REENTRY_SLOT)
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
            pragma solidity ^0.8.0;
            import "../IERC20.sol";
            import "../extensions/IERC20Permit.sol";
            import "../../../utils/Address.sol";
            /**
             * @title SafeERC20
             * @dev Wrappers around ERC20 operations that throw on failure (when the token
             * contract returns false). Tokens that return no value (and instead revert or
             * throw on failure) are also supported, non-reverting calls are assumed to be
             * successful.
             * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
             * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
             */
            library SafeERC20 {
                using Address for address;
                /**
                 * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
                 * non-reverting calls are assumed to be successful.
                 */
                function safeTransfer(IERC20 token, address to, uint256 value) internal {
                    _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                }
                /**
                 * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
                 * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
                 */
                function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                    _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                }
                /**
                 * @dev Deprecated. This function has issues similar to the ones found in
                 * {IERC20-approve}, and its usage is discouraged.
                 *
                 * Whenever possible, use {safeIncreaseAllowance} and
                 * {safeDecreaseAllowance} instead.
                 */
                function safeApprove(IERC20 token, address spender, uint256 value) internal {
                    // safeApprove should only be called when setting an initial allowance,
                    // or when resetting it to zero. To increase and decrease it, use
                    // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                    require(
                        (value == 0) || (token.allowance(address(this), spender) == 0),
                        "SafeERC20: approve from non-zero to non-zero allowance"
                    );
                    _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                }
                /**
                 * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
                 * non-reverting calls are assumed to be successful.
                 */
                function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                    uint256 oldAllowance = token.allowance(address(this), spender);
                    _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
                }
                /**
                 * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
                 * non-reverting calls are assumed to be successful.
                 */
                function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                    unchecked {
                        uint256 oldAllowance = token.allowance(address(this), spender);
                        require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
                    }
                }
                /**
                 * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
                 * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
                 * to be set to zero before setting it to a non-zero value, such as USDT.
                 */
                function forceApprove(IERC20 token, address spender, uint256 value) internal {
                    bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
                    if (!_callOptionalReturnBool(token, approvalCall)) {
                        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
                        _callOptionalReturn(token, approvalCall);
                    }
                }
                /**
                 * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
                 * Revert on invalid signature.
                 */
                function safePermit(
                    IERC20Permit token,
                    address owner,
                    address spender,
                    uint256 value,
                    uint256 deadline,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) internal {
                    uint256 nonceBefore = token.nonces(owner);
                    token.permit(owner, spender, value, deadline, v, r, s);
                    uint256 nonceAfter = token.nonces(owner);
                    require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
                }
                /**
                 * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                 * on the return value: the return value is optional (but if data is returned, it must not be false).
                 * @param token The token targeted by the call.
                 * @param data The call data (encoded using abi.encode or one of its variants).
                 */
                function _callOptionalReturn(IERC20 token, bytes memory data) private {
                    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                    // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
                    // the target address contains contract code and also asserts for success in the low-level call.
                    bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                    require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                }
                /**
                 * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                 * on the return value: the return value is optional (but if data is returned, it must not be false).
                 * @param token The token targeted by the call.
                 * @param data The call data (encoded using abi.encode or one of its variants).
                 *
                 * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
                 */
                function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
                    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                    // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
                    // and not revert is the subcall reverts.
                    (bool success, bytes memory returndata) = address(token).call(data);
                    return
                        success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
            import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
            import "./IResolver.sol";
            /// @title EssentialContract
            /// @custom:security-contact [email protected]
            abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable {
                uint8 internal constant _FALSE = 1;
                uint8 internal constant _TRUE = 2;
                address private immutable __resolver;
                uint256[50] private __gapFromOldAddressResolver;
                /// @dev Slot 1.
                uint8 internal __reentry;
                uint8 internal __paused;
                uint256[49] private __gap;
                /// @notice Emitted when the contract is paused.
                /// @param account The account that paused the contract.
                event Paused(address account);
                /// @notice Emitted when the contract is unpaused.
                /// @param account The account that unpaused the contract.
                event Unpaused(address account);
                error INVALID_PAUSE_STATUS();
                error FUNC_NOT_IMPLEMENTED();
                error REENTRANT_CALL();
                error ACCESS_DENIED();
                error RESOLVER_NOT_FOUND();
                error ZERO_ADDRESS();
                error ZERO_VALUE();
                /// @dev Modifier that ensures the caller is the owner or resolved address of a given name.
                /// @param _name The name to check against.
                modifier onlyFromOwnerOrNamed(bytes32 _name) {
                    require(msg.sender == owner() || msg.sender == resolve(_name, true), ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is either the owner or a specified address.
                /// @param _addr The address to check against.
                modifier onlyFromOwnerOr(address _addr) {
                    require(msg.sender == owner() || msg.sender == _addr, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that reverts the function call, indicating it is not implemented.
                modifier notImplemented() {
                    revert FUNC_NOT_IMPLEMENTED();
                    _;
                }
                /// @dev Modifier that prevents reentrant calls to a function.
                modifier nonReentrant() {
                    require(_loadReentryLock() != _TRUE, REENTRANT_CALL());
                    _storeReentryLock(_TRUE);
                    _;
                    _storeReentryLock(_FALSE);
                }
                /// @dev Modifier that allows function execution only when the contract is paused.
                modifier whenPaused() {
                    require(paused(), INVALID_PAUSE_STATUS());
                    _;
                }
                /// @dev Modifier that allows function execution only when the contract is not paused.
                modifier whenNotPaused() {
                    require(!paused(), INVALID_PAUSE_STATUS());
                    _;
                }
                /// @dev Modifier that ensures the provided address is not the zero address.
                /// @param _addr The address to check.
                modifier nonZeroAddr(address _addr) {
                    require(_addr != address(0), ZERO_ADDRESS());
                    _;
                }
                /// @dev Modifier that ensures the provided value is not zero.
                /// @param _value The value to check.
                modifier nonZeroValue(uint256 _value) {
                    require(_value != 0, ZERO_VALUE());
                    _;
                }
                /// @dev Modifier that ensures the provided bytes32 value is not zero.
                /// @param _value The bytes32 value to check.
                modifier nonZeroBytes32(bytes32 _value) {
                    require(_value != 0, ZERO_VALUE());
                    _;
                }
                /// @dev Modifier that ensures the caller is the resolved address of a given
                /// name.
                /// @param _name The name to check against.
                modifier onlyFromNamed(bytes32 _name) {
                    require(msg.sender == resolve(_name, true), ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is the resolved address of a given
                /// name, if the name is set.
                /// @param _name The name to check against.
                modifier onlyFromOptionalNamed(bytes32 _name) {
                    address addr = resolve(_name, true);
                    require(addr == address(0) || msg.sender == addr, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is a resolved address to either _name1 or _name2
                /// name.
                /// @param _name1 The first name to check against.
                /// @param _name2 The second name to check against.
                modifier onlyFromNamedEither(bytes32 _name1, bytes32 _name2) {
                    require(
                        msg.sender == resolve(_name1, true) || msg.sender == resolve(_name2, true),
                        ACCESS_DENIED()
                    );
                    _;
                }
                /// @dev Modifier that ensures the caller is either of the two specified addresses.
                /// @param _addr1 The first address to check against.
                /// @param _addr2 The second address to check against.
                modifier onlyFromEither(address _addr1, address _addr2) {
                    require(msg.sender == _addr1 || msg.sender == _addr2, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is the specified address.
                /// @param _addr The address to check against.
                modifier onlyFrom(address _addr) {
                    require(msg.sender == _addr, ACCESS_DENIED());
                    _;
                }
                /// @dev Modifier that ensures the caller is the specified address.
                /// @param _addr The address to check against.
                modifier onlyFromOptional(address _addr) {
                    require(_addr == address(0) || msg.sender == _addr, ACCESS_DENIED());
                    _;
                }
                constructor(address _resolver) {
                    __resolver = _resolver;
                    _disableInitializers();
                }
                /// @notice Pauses the contract.
                function pause() public whenNotPaused {
                    _pause();
                    emit Paused(msg.sender);
                    // We call the authorize function here to avoid:
                    // Warning (5740): Unreachable code.
                    _authorizePause(msg.sender, true);
                }
                /// @notice Unpauses the contract.
                function unpause() public whenPaused {
                    _unpause();
                    emit Unpaused(msg.sender);
                    // We call the authorize function here to avoid:
                    // Warning (5740): Unreachable code.
                    _authorizePause(msg.sender, false);
                }
                function impl() public view returns (address) {
                    return _getImplementation();
                }
                /// @notice Returns true if the contract is paused, and false otherwise.
                /// @return true if paused, false otherwise.
                function paused() public view virtual returns (bool) {
                    return __paused == _TRUE;
                }
                function inNonReentrant() public view returns (bool) {
                    return _loadReentryLock() == _TRUE;
                }
                /// @notice Returns the address of this contract.
                /// @return The address of this contract.
                function resolver() public view virtual returns (address) {
                    return __resolver;
                }
                /// @notice Resolves a name to an address on a specific chain
                /// @param _chainId The chain ID to resolve the name on
                /// @param _name The name to resolve
                /// @param _allowZeroAddress Whether to allow resolving to the zero address
                /// @return The resolved address
                function resolve(
                    uint64 _chainId,
                    bytes32 _name,
                    bool _allowZeroAddress
                )
                    internal
                    view
                    returns (address)
                {
                    return IResolver(resolver()).resolve(_chainId, _name, _allowZeroAddress);
                }
                /// @notice Resolves a name to an address on the current chain
                /// @param _name The name to resolve
                /// @param _allowZeroAddress Whether to allow resolving to the zero address
                /// @return The resolved address
                function resolve(bytes32 _name, bool _allowZeroAddress) internal view returns (address) {
                    return IResolver(resolver()).resolve(block.chainid, _name, _allowZeroAddress);
                }
                /// @notice Initializes the contract.
                /// @param _owner The owner of this contract. msg.sender will be used if this value is zero.
                function __Essential_init(address _owner) internal virtual onlyInitializing {
                    __Context_init();
                    _transferOwnership(_owner == address(0) ? msg.sender : _owner);
                    __paused = _FALSE;
                }
                function _pause() internal virtual {
                    __paused = _TRUE;
                }
                function _unpause() internal virtual {
                    __paused = _FALSE;
                }
                function _authorizeUpgrade(address) internal virtual override onlyOwner { }
                function _authorizePause(address, bool) internal virtual onlyOwner { }
                // Stores the reentry lock
                function _storeReentryLock(uint8 _reentry) internal virtual {
                    __reentry = _reentry;
                }
                // Loads the reentry lock
                function _loadReentryLock() internal view virtual returns (uint8 reentry_) {
                    reentry_ = __reentry;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title ITaiko
            /// @notice This interface is used for contracts identified by the "taiko" label in the address
            /// resolver, specifically the TaikoInbox and TaikoAnchor contracts.
            /// @custom:security-contact [email protected]
            interface ITaiko {
                /// @notice Determines the operational layer of the contract, whether it is on Layer 1 (L1) or
                /// Layer 2 (L2).
                /// @return True if the contract is operating on L1, false if on L2.
                function isOnL1() external pure returns (bool);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
            /// @title LibAddress
            /// @dev Provides utilities for address-related operations.
            /// @custom:security-contact [email protected]
            library LibAddress {
                error ETH_TRANSFER_FAILED();
                /// @dev Sends Ether to the specified address. This method will not revert even if sending ether
                /// fails.
                /// This function is inspired by
                /// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol
                /// @param _to The recipient address.
                /// @param _amount The amount of Ether to send in wei.
                /// @param _gasLimit The max amount gas to pay for this transaction.
                /// @return success_ true if the call is successful, false otherwise.
                function sendEther(
                    address _to,
                    uint256 _amount,
                    uint256 _gasLimit,
                    bytes memory _calldata
                )
                    internal
                    returns (bool success_)
                {
                    // Check for zero-address transactions
                    require(_to != address(0), ETH_TRANSFER_FAILED());
                    // dispatch message to recipient
                    // by assembly calling "handle" function
                    // we call via assembly to avoid memcopying a very large returndata
                    // returned by a malicious contract
                    assembly {
                        success_ :=
                            call(
                                _gasLimit, // gas
                                _to, // recipient
                                _amount, // ether value
                                add(_calldata, 0x20), // inloc
                                mload(_calldata), // inlen
                                0, // outloc
                                0 // outlen
                            )
                    }
                }
                /// @dev Sends Ether to the specified address. This method will revert if sending ether fails.
                /// @param _to The recipient address.
                /// @param _amount The amount of Ether to send in wei.
                /// @param _gasLimit The max amount gas to pay for this transaction.
                function sendEtherAndVerify(address _to, uint256 _amount, uint256 _gasLimit) internal {
                    if (_amount == 0) return;
                    require(sendEther(_to, _amount, _gasLimit, ""), ETH_TRANSFER_FAILED());
                }
                /// @dev Sends Ether to the specified address. This method will revert if sending ether fails.
                /// @param _to The recipient address.
                /// @param _amount The amount of Ether to send in wei.
                function sendEtherAndVerify(address _to, uint256 _amount) internal {
                    sendEtherAndVerify(_to, _amount, gasleft());
                }
                function supportsInterface(
                    address _addr,
                    bytes4 _interfaceId
                )
                    internal
                    view
                    returns (bool result_)
                {
                    (bool success, bytes memory data) =
                        _addr.staticcall(abi.encodeCall(IERC165.supportsInterface, (_interfaceId)));
                    if (success && data.length == 32) {
                        result_ = abi.decode(data, (bool));
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title LibMath
            /// @dev This library offers additional math functions for uint256.
            /// @custom:security-contact [email protected]
            library LibMath {
                /// @dev Returns the smaller of the two given values.
                /// @param _a The first number to compare.
                /// @param _b The second number to compare.
                /// @return The smaller of the two numbers.
                function min(uint256 _a, uint256 _b) internal pure returns (uint256) {
                    return _a > _b ? _b : _a;
                }
                /// @dev Returns the larger of the two given values.
                /// @param _a The first number to compare.
                /// @param _b The second number to compare.
                /// @return The larger of the two numbers.
                function max(uint256 _a, uint256 _b) internal pure returns (uint256) {
                    return _a > _b ? _a : _b;
                }
                function capToUint64(uint256 _value) internal pure returns (uint64) {
                    return uint64(min(_value, type(uint64).max));
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title LibStrings
            /// @custom:security-contact [email protected]
            library LibStrings {
                bytes32 internal constant B_AUTOMATA_DCAP_ATTESTATION = bytes32("automata_dcap_attestation");
                bytes32 internal constant B_SGX_GETH_AUTOMATA = bytes32("sgx_geth_automata");
                bytes32 internal constant B_BOND_TOKEN = bytes32("bond_token");
                bytes32 internal constant B_BRIDGE = bytes32("bridge");
                bytes32 internal constant B_BRIDGE_WATCHDOG = bytes32("bridge_watchdog");
                bytes32 internal constant B_BRIDGED_ERC1155 = bytes32("bridged_erc1155");
                bytes32 internal constant B_BRIDGED_ERC20 = bytes32("bridged_erc20");
                bytes32 internal constant B_BRIDGED_ERC721 = bytes32("bridged_erc721");
                bytes32 internal constant B_CHAIN_WATCHDOG = bytes32("chain_watchdog");
                bytes32 internal constant B_ERC1155_VAULT = bytes32("erc1155_vault");
                bytes32 internal constant B_ERC20_VAULT = bytes32("erc20_vault");
                bytes32 internal constant B_ERC721_VAULT = bytes32("erc721_vault");
                bytes32 internal constant B_FORCED_INCLUSION_STORE = bytes32("forced_inclusion_store");
                bytes32 internal constant B_PRECONF_WHITELIST = bytes32("preconf_whitelist");
                bytes32 internal constant B_PRECONF_WHITELIST_OWNER = bytes32("preconf_whitelist_owner");
                bytes32 internal constant B_PRECONF_ROUTER = bytes32("preconf_router");
                bytes32 internal constant B_TAIKO_WRAPPER = bytes32("taiko_wrapper");
                bytes32 internal constant B_PROOF_VERIFIER = bytes32("proof_verifier");
                bytes32 internal constant B_SGX_RETH_VERIFIER = bytes32("sgx_reth_verifier");
                bytes32 internal constant B_SGX_GETH_VERIFIER = bytes32("sgx_geth_verifier");
                bytes32 internal constant B_RISC0_RETH_VERIFIER = bytes32("risc0_reth_verifier");
                bytes32 internal constant B_SP1_RETH_VERIFIER = bytes32("sp1_reth_verifier");
                bytes32 internal constant B_PROVER_SET = bytes32("prover_set");
                bytes32 internal constant B_QUOTA_MANAGER = bytes32("quota_manager");
                bytes32 internal constant B_SIGNAL_SERVICE = bytes32("signal_service");
                bytes32 internal constant B_TAIKO = bytes32("taiko");
                bytes32 internal constant B_TAIKO_TOKEN = bytes32("taiko_token");
                bytes32 internal constant B_WITHDRAWER = bytes32("withdrawer");
                bytes32 internal constant H_SIGNAL_ROOT = keccak256("SIGNAL_ROOT");
                bytes32 internal constant H_STATE_ROOT = keccak256("STATE_ROOT");
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title ISignalService
            /// @notice The SignalService contract serves as a secure cross-chain message
            /// passing system. It defines methods for sending and verifying signals with
            /// merkle proofs. The trust assumption is that the target chain has secure
            /// access to the merkle root (such as Taiko injects it in the anchor
            /// transaction). With this, verifying a signal is reduced to simply verifying
            /// a merkle proof.
            /// @custom:security-contact [email protected]
            interface ISignalService {
                enum CacheOption {
                    CACHE_NOTHING,
                    CACHE_SIGNAL_ROOT,
                    CACHE_STATE_ROOT,
                    CACHE_BOTH
                }
                struct HopProof {
                    /// @notice This hop's destination chain ID. If there is a next hop, this ID is the next
                    /// hop's source chain ID.
                    uint64 chainId;
                    /// @notice The ID of a source chain block whose state root has been synced to the hop's
                    /// destination chain.
                    /// Note that this block ID must be greater than or equal to the block ID where the signal
                    /// was sent on the source chain.
                    uint64 blockId;
                    /// @notice The state root or signal root of the source chain at the above blockId. This
                    /// value has been synced to the destination chain.
                    /// @dev To get both the blockId and the rootHash, apps should subscribe to the
                    /// ChainDataSynced event or query `topBlockId` first using the source chain's ID and
                    /// LibStrings.H_STATE_ROOT to get the most recent block ID synced, then call
                    /// `getSyncedChainData` to read the synchronized data.
                    bytes32 rootHash;
                    /// @notice Options to cache either the state roots or signal roots of middle-hops to the
                    /// current chain.
                    CacheOption cacheOption;
                    /// @notice The signal service's account proof. If this value is empty, then `rootHash` will
                    /// be used as the signal root, otherwise, `rootHash` will be used as the state root.
                    bytes[] accountProof;
                    /// @notice The signal service's storage proof.
                    bytes[] storageProof;
                }
                /// @notice Emitted when a remote chain's state root or signal root is
                /// synced locally as a signal.
                /// @param chainId The remote chainId.
                /// @param blockId The chain data's corresponding blockId.
                /// @param kind A value to mark the data type.
                /// @param data The remote data.
                /// @param signal The signal for this chain data.
                event ChainDataSynced(
                    uint64 indexed chainId,
                    uint64 indexed blockId,
                    bytes32 indexed kind,
                    bytes32 data,
                    bytes32 signal
                );
                /// @notice Emitted when signals are received directly by TaikoL2 in its Anchor transaction.
                /// @param signalSlots The signal slots that were received.
                event SignalsReceived(bytes32[] signalSlots);
                /// @notice Emitted when a signal is sent.
                /// @param app The address that initiated the signal.
                /// @param signal The signal (message) that was sent.
                /// @param slot The location in storage where this signal is stored.
                /// @param value The value of the signal.
                event SignalSent(address app, bytes32 signal, bytes32 slot, bytes32 value);
                /// @notice Emitted when an address is authorized or deauthorized.
                /// @param addr The address to be authorized or deauthorized.
                /// @param authorized True if authorized, false otherwise.
                event Authorized(address indexed addr, bool authorized);
                /// @dev Allow TaikoL2 to receive signals directly in its Anchor transaction.
                /// @param _signalSlots The signal slots to mark as received.
                function receiveSignals(bytes32[] calldata _signalSlots) external;
                /// @notice Send a signal (message) by setting the storage slot to the same value as the signal
                /// itself.
                /// @param _signal The signal (message) to send.
                /// @return slot_ The location in storage where this signal is stored.
                function sendSignal(bytes32 _signal) external returns (bytes32 slot_);
                /// @notice Sync a data from a remote chain locally as a signal. The signal is calculated
                /// uniquely from chainId, kind, and data.
                /// @param _chainId The remote chainId.
                /// @param _kind A value to mark the data type.
                /// @param _blockId The chain data's corresponding blockId
                /// @param _chainData The remote data.
                /// @return signal_ The signal for this chain data.
                function syncChainData(
                    uint64 _chainId,
                    bytes32 _kind,
                    uint64 _blockId,
                    bytes32 _chainData
                )
                    external
                    returns (bytes32 signal_);
                /// @notice Verifies if a signal has been received on the target chain.
                /// @param _chainId The identifier for the source chain from which the
                /// signal originated.
                /// @param _app The address that initiated the signal.
                /// @param _signal The signal (message) to send.
                /// @param _proof Merkle proof that the signal was persisted on the
                /// source chain. If this proof is empty, then we check if this signal has been marked as
                /// received by TaikoL2.
                /// @return numCacheOps_ The number of newly cached items.
                function proveSignalReceived(
                    uint64 _chainId,
                    address _app,
                    bytes32 _signal,
                    bytes calldata _proof
                )
                    external
                    returns (uint256 numCacheOps_);
                /// @notice Verifies if a signal has been received on the target chain.
                /// This is the "readonly" version of proveSignalReceived.
                /// @param _chainId The identifier for the source chain from which the
                /// signal originated.
                /// @param _app The address that initiated the signal.
                /// @param _signal The signal (message) to send.
                /// @param _proof Merkle proof that the signal was persisted on the
                /// source chain. If this proof is empty, then we check if this signal has been marked as
                /// received by TaikoL2.
                function verifySignalReceived(
                    uint64 _chainId,
                    address _app,
                    bytes32 _signal,
                    bytes calldata _proof
                )
                    external
                    view;
                /// @notice Verifies if a particular signal has already been sent.
                /// @param _app The address that initiated the signal.
                /// @param _signal The signal (message) that was sent.
                /// @return true if the signal has been sent, otherwise false.
                function isSignalSent(address _app, bytes32 _signal) external view returns (bool);
                /// @notice Verifies if a particular signal has already been sent.
                /// @param _signalSlot The location in storage where this signal is stored.
                function isSignalSent(bytes32 _signalSlot) external view returns (bool);
                /// @notice Checks if a chain data has been synced.
                /// @param _chainId The remote chainId.
                /// @param _kind A value to mark the data type.
                /// @param _blockId The chain data's corresponding blockId
                /// @param _chainData The remote data.
                /// @return true if the data has been synced, otherwise false.
                function isChainDataSynced(
                    uint64 _chainId,
                    bytes32 _kind,
                    uint64 _blockId,
                    bytes32 _chainData
                )
                    external
                    view
                    returns (bool);
                /// @notice Returns the given block's  chain data.
                /// @param _chainId Identifier of the chainId.
                /// @param _kind A value to mark the data type.
                /// @param _blockId The chain data's corresponding block id. If this value is 0, use the top
                /// block id.
                /// @return blockId_ The actual block id.
                /// @return chainData_ The synced chain data.
                function getSyncedChainData(
                    uint64 _chainId,
                    bytes32 _kind,
                    uint64 _blockId
                )
                    external
                    view
                    returns (uint64 blockId_, bytes32 chainData_);
                /// @notice Returns the data to be used for caching slot generation.
                /// @param _chainId Identifier of the chainId.
                /// @param _kind A value to mark the data type.
                /// @param _blockId The chain data's corresponding block id. If this value is 0, use the top
                /// block id.
                /// @return signal_ The signal used for caching slot creation.
                function signalForChainData(
                    uint64 _chainId,
                    bytes32 _kind,
                    uint64 _blockId
                )
                    external
                    pure
                    returns (bytes32 signal_);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "../based/ITaikoInbox.sol";
            /// @title IVerifier
            /// @notice Defines the function that handles proof verification.
            /// @custom:security-contact [email protected]
            interface IVerifier {
                struct Context {
                    uint64 batchId;
                    bytes32 metaHash;
                    ITaikoInbox.Transition transition;
                }
                /// @notice Verifies multiple proofs. This function must throw if the proof cannot be verified.
                /// @param _ctxs The array of contexts for the proof verifications.
                /// @param _proof The batch proof to verify.
                function verifyProof(Context[] calldata _ctxs, bytes calldata _proof) external;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "src/shared/based/LibSharedData.sol";
            /// @title TaikoInbox
            /// @notice Acts as the inbox for the Taiko Alethia protocol, a simplified version of the
            /// original Taiko-Based Contestable Rollup (BCR). The tier-based proof system and
            /// contestation mechanisms have been removed.
            ///
            /// Key assumptions of this protocol:
            /// - Block proposals and proofs are asynchronous. Proofs are not available at proposal time,
            ///   unlike Taiko Gwyneth, which assumes synchronous composability.
            /// - Proofs are presumed error-free and thoroughly validated, with proof type management
            ///   delegated to IVerifier contracts.
            ///
            /// @dev Registered in the address resolver as "taiko".
            /// @custom:security-contact [email protected]
            interface ITaikoInbox {
                struct BlockParams {
                    // the max number of transactions in this block. Note that if there are not enough
                    // transactions in calldata or blobs, the block will contains as many transactions as
                    // possible.
                    uint16 numTransactions;
                    // The time difference (in seconds) between the timestamp of this block and
                    // the timestamp of the parent block in the same batch. For the first block in a batch,
                    // there is not parent block in the same batch, so the time shift should be 0.
                    uint8 timeShift;
                    // Signals sent on L1 and need to sync to this L2 block.
                    bytes32[] signalSlots;
                }
                struct BlobParams {
                    // The hashes of the blob. Note that if this array is not empty.  `firstBlobIndex` and
                    // `numBlobs` must be 0.
                    bytes32[] blobHashes;
                    // The index of the first blob in this batch.
                    uint8 firstBlobIndex;
                    // The number of blobs in this batch. Blobs are initially concatenated and subsequently
                    // decompressed via Zlib.
                    uint8 numBlobs;
                    // The byte offset of the blob in the batch.
                    uint32 byteOffset;
                    // The byte size of the blob.
                    uint32 byteSize;
                    // The block number when the blob was created. This value is only non-zero when
                    // `blobHashes` are non-empty.
                    uint64 createdIn;
                }
                struct BatchParams {
                    address proposer;
                    address coinbase;
                    bytes32 parentMetaHash;
                    uint64 anchorBlockId;
                    uint64 lastBlockTimestamp;
                    bool revertIfNotFirstProposal;
                    // Specifies the number of blocks to be generated from this batch.
                    BlobParams blobParams;
                    BlockParams[] blocks;
                }
                /// @dev This struct holds batch information essential for constructing blocks offchain, but it
                /// does not include data necessary for batch proving.
                struct BatchInfo {
                    bytes32 txsHash;
                    // Data to build L2 blocks
                    BlockParams[] blocks;
                    bytes32[] blobHashes;
                    bytes32 extraData;
                    address coinbase;
                    uint64 proposedIn; // Used by node/client
                    uint64 blobCreatedIn;
                    uint32 blobByteOffset;
                    uint32 blobByteSize;
                    uint32 gasLimit;
                    uint64 lastBlockId;
                    uint64 lastBlockTimestamp;
                    // Data for the L2 anchor transaction, shared by all blocks in the batch
                    uint64 anchorBlockId;
                    // corresponds to the `_anchorStateRoot` parameter in the anchor transaction.
                    // The batch's validity proof shall verify the integrity of these two values.
                    bytes32 anchorBlockHash;
                    LibSharedData.BaseFeeConfig baseFeeConfig;
                }
                /// @dev This struct holds batch metadata essential for proving the batch.
                struct BatchMetadata {
                    bytes32 infoHash;
                    address proposer;
                    uint64 batchId;
                    uint64 proposedAt; // Used by node/client
                }
                /// @notice Struct representing transition to be proven.
                struct Transition {
                    bytes32 parentHash;
                    bytes32 blockHash;
                    bytes32 stateRoot;
                }
                //  @notice Struct representing transition storage
                /// @notice 4 slots used.
                struct TransitionState {
                    bytes32 parentHash;
                    bytes32 blockHash;
                    bytes32 stateRoot;
                    address prover;
                    bool inProvingWindow;
                    uint48 createdAt;
                }
                /// @notice 3 slots used.
                struct Batch {
                    bytes32 metaHash; // slot 1
                    uint64 lastBlockId; // slot 2
                    uint96 reserved3;
                    uint96 livenessBond;
                    uint64 batchId; // slot 3
                    uint64 lastBlockTimestamp;
                    uint64 anchorBlockId;
                    uint24 nextTransitionId;
                    uint8 reserved4;
                    // The ID of the transaction that is used to verify this batch. However, if this batch is
                    // not verified as the last one in a transaction, verifiedTransitionId will remain zero.
                    uint24 verifiedTransitionId;
                }
                /// @notice Forge is only able to run coverage in case the contracts by default capable of
                /// compiling without any optimization (neither optimizer runs, no compiling --via-ir flag).
                struct Stats1 {
                    uint64 genesisHeight;
                    uint64 __reserved2;
                    uint64 lastSyncedBatchId;
                    uint64 lastSyncedAt;
                }
                struct Stats2 {
                    uint64 numBatches;
                    uint64 lastVerifiedBatchId;
                    bool paused;
                    uint56 lastProposedIn;
                    uint64 lastUnpausedAt;
                }
                struct ForkHeights {
                    uint64 ontake; // measured with block number.
                    uint64 pacaya; // measured with the batch Id, not block number.
                    uint64 shasta; // measured with the batch Id, not block number.
                    uint64 unzen; // measured with the batch Id, not block number.
                }
                /// @notice Struct holding Taiko configuration parameters. See {TaikoConfig}.
                struct Config {
                    /// @notice The chain ID of the network where Taiko contracts are deployed.
                    uint64 chainId;
                    /// @notice The maximum number of unverified batches the protocol supports.
                    uint64 maxUnverifiedBatches;
                    /// @notice Size of the batch ring buffer, allowing extra space for proposals.
                    uint64 batchRingBufferSize;
                    /// @notice The maximum number of verifications allowed when a batch is proposed or proved.
                    uint64 maxBatchesToVerify;
                    /// @notice The maximum gas limit allowed for a block.
                    uint32 blockMaxGasLimit;
                    /// @notice The amount of Taiko token as a prover liveness bond per batch.
                    uint96 livenessBondBase;
                    /// @notice The amount of Taiko token as a prover liveness bond per block. This field is
                    /// deprecated and its value will be ignored.
                    uint96 livenessBondPerBlock;
                    /// @notice The number of batches between two L2-to-L1 state root sync.
                    uint8 stateRootSyncInternal;
                    /// @notice The max differences of the anchor height and the current block number.
                    uint64 maxAnchorHeightOffset;
                    /// @notice Base fee configuration
                    LibSharedData.BaseFeeConfig baseFeeConfig;
                    /// @notice The proving window in seconds.
                    uint16 provingWindow;
                    /// @notice The time required for a transition to be used for verifying a batch.
                    uint24 cooldownWindow;
                    /// @notice The maximum number of signals to be received by TaikoL2.
                    uint8 maxSignalsToReceive;
                    /// @notice The maximum number of blocks per batch.
                    uint16 maxBlocksPerBatch;
                    /// @notice Historical heights of the forks.
                    ForkHeights forkHeights;
                }
                /// @notice Struct holding the state variables for the {Taiko} contract.
                struct State {
                    // Ring buffer for proposed batches and a some recent verified batches.
                    mapping(uint256 batchId_mod_batchRingBufferSize => Batch batch) batches;
                    // Indexing to transition ids (ring buffer not possible)
                    mapping(uint256 batchId => mapping(bytes32 parentHash => uint24 transitionId)) transitionIds;
                    // Ring buffer for transitions
                    mapping(
                        uint256 batchId_mod_batchRingBufferSize
                            => mapping(uint24 transitionId => TransitionState ts)
                    ) transitions;
                    bytes32 __reserve1; // slot 4 - was used as a ring buffer for Ether deposits
                    Stats1 stats1; // slot 5
                    Stats2 stats2; // slot 6
                    mapping(address account => uint256 bond) bondBalance;
                    uint256[43] __gap;
                }
                /// @notice Emitted when tokens are deposited into a user's bond balance.
                /// @param user The address of the user who deposited the tokens.
                /// @param amount The amount of tokens deposited.
                event BondDeposited(address indexed user, uint256 amount);
                /// @notice Emitted when tokens are withdrawn from a user's bond balance.
                /// @param user The address of the user who withdrew the tokens.
                /// @param amount The amount of tokens withdrawn.
                event BondWithdrawn(address indexed user, uint256 amount);
                /// @notice Emitted when a token is credited back to a user's bond balance.
                /// @param user The address of the user whose bond balance is credited.
                /// @param amount The amount of tokens credited.
                event BondCredited(address indexed user, uint256 amount);
                /// @notice Emitted when a token is debited from a user's bond balance.
                /// @param user The address of the user whose bond balance is debited.
                /// @param amount The amount of tokens debited.
                event BondDebited(address indexed user, uint256 amount);
                /// @notice Emitted when a batch is synced.
                /// @param stats1 The Stats1 data structure.
                event Stats1Updated(Stats1 stats1);
                /// @notice Emitted when some state variable values changed.
                /// @param stats2 The Stats2 data structure.
                event Stats2Updated(Stats2 stats2);
                /// @notice Emitted when a batch is proposed.
                /// @param info The info of the proposed batch.
                /// @param meta The metadata of the proposed batch.
                /// @param txList The tx list in calldata.
                event BatchProposed(BatchInfo info, BatchMetadata meta, bytes txList);
                /// @notice Emitted when multiple transitions are proved.
                /// @param verifier The address of the verifier.
                /// @param transitions The transitions data.
                event BatchesProved(address verifier, uint64[] batchIds, Transition[] transitions);
                /// @notice Emitted when a transition is overwritten by a conflicting one with the same parent
                /// hash but different block hash or state root.
                /// @param batchId The batch ID.
                /// @param oldTran The old transition overwritten.
                /// @param newTran The new transition.
                event ConflictingProof(uint64 batchId, TransitionState oldTran, Transition newTran);
                /// @notice Emitted when a batch is verified.
                /// @param batchId The ID of the verified batch.
                /// @param blockHash The hash of the verified batch.
                event BatchesVerified(uint64 batchId, bytes32 blockHash);
                error AnchorBlockIdSmallerThanParent();
                error AnchorBlockIdTooLarge();
                error AnchorBlockIdTooSmall();
                error ArraySizesMismatch();
                error BatchNotFound();
                error BatchVerified();
                error BeyondCurrentFork();
                error BlobNotFound();
                error BlockNotFound();
                error BlobNotSpecified();
                error ContractPaused();
                error CustomProposerMissing();
                error CustomProposerNotAllowed();
                error EtherNotPaidAsBond();
                error FirstBlockTimeShiftNotZero();
                error ForkNotActivated();
                error InsufficientBond();
                error InvalidBlobCreatedIn();
                error InvalidBlobParams();
                error InvalidGenesisBlockHash();
                error InvalidParams();
                error InvalidTransitionBlockHash();
                error InvalidTransitionParentHash();
                error InvalidTransitionStateRoot();
                error MetaHashMismatch();
                error MsgValueNotZero();
                error NoBlocksToProve();
                error NotFirstProposal();
                error NotInboxWrapper();
                error ParentMetaHashMismatch();
                error SameTransition();
                error SignalNotSent();
                error TimestampSmallerThanParent();
                error TimestampTooLarge();
                error TimestampTooSmall();
                error TooManyBatches();
                error TooManyBlocks();
                error TooManySignals();
                error TransitionNotFound();
                error ZeroAnchorBlockHash();
                /// @notice Proposes a batch of blocks.
                /// @param _params ABI-encoded parameters.
                /// @param _txList The transaction list in calldata. If the txList is empty, blob will be used
                /// for data availability.
                /// @return info_ The info of the proposed batch.
                /// @return meta_ The metadata of the proposed batch.
                function proposeBatch(
                    bytes calldata _params,
                    bytes calldata _txList
                )
                    external
                    returns (ITaikoInbox.BatchInfo memory info_, ITaikoInbox.BatchMetadata memory meta_);
                /// @notice Proves state transitions for multiple batches with a single aggregated proof.
                /// @param _params ABI-encoded parameter containing:
                /// - metas: Array of metadata for each batch being proved.
                /// - transitions: Array of batch transitions to be proved.
                /// @param _proof The aggregated cryptographic proof proving the batches transitions.
                function proveBatches(bytes calldata _params, bytes calldata _proof) external;
                /// @notice Deposits TAIKO tokens into the contract to be used as liveness bond.
                /// @param _amount The amount of TAIKO tokens to deposit.
                function depositBond(uint256 _amount) external payable;
                /// @notice Withdraws a specified amount of TAIKO tokens from the contract.
                /// @param _amount The amount of TAIKO tokens to withdraw.
                function withdrawBond(uint256 _amount) external;
                /// @notice Returns the TAIKO token balance of a specific user.
                /// @param _user The address of the user.
                /// @return The TAIKO token balance of the user.
                function bondBalanceOf(address _user) external view returns (uint256);
                /// @notice Retrieves the Bond token address. If Ether is used as bond, this function returns
                /// address(0).
                /// @return The Bond token address.
                function bondToken() external view returns (address);
                /// @notice Retrieves the first set of protocol statistics.
                /// @return Stats1 structure containing the statistics.
                function getStats1() external view returns (Stats1 memory);
                /// @notice Retrieves the second set of protocol statistics.
                /// @return Stats2 structure containing the statistics.
                function getStats2() external view returns (Stats2 memory);
                /// @notice Retrieves data about a specific batch.
                /// @param _batchId The ID of the batch to retrieve.
                /// @return batch_ The batch data.
                function getBatch(uint64 _batchId) external view returns (Batch memory batch_);
                /// @notice Retrieves a specific transition by batch ID and transition ID. This function may
                /// revert if the transition is not found.
                /// @param _batchId The batch ID.
                /// @param _tid The transition ID.
                /// @return The specified transition state.
                function getTransitionById(
                    uint64 _batchId,
                    uint24 _tid
                )
                    external
                    view
                    returns (ITaikoInbox.TransitionState memory);
                /// @notice Retrieves a specific transition by batch ID and parent Hash. This function may
                /// revert if the transition is not found.
                /// @param _batchId The batch ID.
                /// @param _parentHash The parent hash.
                /// @return The specified transition state.
                function getTransitionByParentHash(
                    uint64 _batchId,
                    bytes32 _parentHash
                )
                    external
                    view
                    returns (ITaikoInbox.TransitionState memory);
                /// @notice Retrieves the transition used for the last verified batch.
                /// @return batchId_ The batch ID of the last verified transition.
                /// @return blockId_ The block ID of the last verified block.
                /// @return ts_ The last verified transition.
                function getLastVerifiedTransition()
                    external
                    view
                    returns (uint64 batchId_, uint64 blockId_, TransitionState memory ts_);
                /// @notice Retrieves the transition used for the last synced batch.
                /// @return batchId_ The batch ID of the last synced transition.
                /// @return blockId_ The block ID of the last synced block.
                /// @return ts_ The last synced transition.
                function getLastSyncedTransition()
                    external
                    view
                    returns (uint64 batchId_, uint64 blockId_, TransitionState memory ts_);
                /// @notice Retrieves the transition used for verifying a batch.
                /// @param _batchId The batch ID.
                /// @return The transition used for verifying the batch.
                function getBatchVerifyingTransition(uint64 _batchId)
                    external
                    view
                    returns (TransitionState memory);
                /// @notice Retrieves the current protocol configuration.
                /// @return The current configuration.
                function pacayaConfig() external view returns (Config memory);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            import "./ITaikoInbox.sol";
            /// @title IProposeBatch
            /// @notice This interface defines the proposeBatch function that is also part of the ITaikoInbox
            /// interface.
            /// @custom:security-contact [email protected]
            interface IProposeBatch {
                /// @notice Proposes a batch of blocks.
                /// @param _params ABI-encoded parameters.
                /// @param _txList The transaction list in calldata. If the txList is empty, blob will be used
                /// for data availability.
                /// @return info_ The info of the proposed batch.
                /// @return meta_ The mmetadata of the proposed batch.
                function proposeBatch(
                    bytes calldata _params,
                    bytes calldata _txList
                )
                    external
                    returns (ITaikoInbox.BatchInfo memory info_, ITaikoInbox.BatchMetadata memory meta_);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Interface of the ERC20 standard as defined in the EIP.
             */
            interface IERC20 {
                /**
                 * @dev Emitted when `value` tokens are moved from one account (`from`) to
                 * another (`to`).
                 *
                 * Note that `value` may be zero.
                 */
                event Transfer(address indexed from, address indexed to, uint256 value);
                /**
                 * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                 * a call to {approve}. `value` is the new allowance.
                 */
                event Approval(address indexed owner, address indexed spender, uint256 value);
                /**
                 * @dev Returns the amount of tokens in existence.
                 */
                function totalSupply() external view returns (uint256);
                /**
                 * @dev Returns the amount of tokens owned by `account`.
                 */
                function balanceOf(address account) external view returns (uint256);
                /**
                 * @dev Moves `amount` tokens from the caller's account to `to`.
                 *
                 * Returns a boolean value indicating whether the operation succeeded.
                 *
                 * Emits a {Transfer} event.
                 */
                function transfer(address to, uint256 amount) external returns (bool);
                /**
                 * @dev Returns the remaining number of tokens that `spender` will be
                 * allowed to spend on behalf of `owner` through {transferFrom}. This is
                 * zero by default.
                 *
                 * This value changes when {approve} or {transferFrom} are called.
                 */
                function allowance(address owner, address spender) external view returns (uint256);
                /**
                 * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                 *
                 * Returns a boolean value indicating whether the operation succeeded.
                 *
                 * IMPORTANT: Beware that changing an allowance with this method brings the risk
                 * that someone may use both the old and the new allowance by unfortunate
                 * transaction ordering. One possible solution to mitigate this race
                 * condition is to first reduce the spender's allowance to 0 and set the
                 * desired value afterwards:
                 * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                 *
                 * Emits an {Approval} event.
                 */
                function approve(address spender, uint256 amount) external returns (bool);
                /**
                 * @dev Moves `amount` tokens from `from` to `to` using the
                 * allowance mechanism. `amount` is then deducted from the caller's
                 * allowance.
                 *
                 * Returns a boolean value indicating whether the operation succeeded.
                 *
                 * Emits a {Transfer} event.
                 */
                function transferFrom(address from, address to, uint256 amount) external returns (bool);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
             * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
             *
             * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
             * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
             * need to send a transaction, and thus is not required to hold Ether at all.
             *
             * ==== Security Considerations
             *
             * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
             * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
             * considered as an intention to spend the allowance in any specific way. The second is that because permits have
             * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
             * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
             * generally recommended is:
             *
             * ```solidity
             * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
             *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
             *     doThing(..., value);
             * }
             *
             * function doThing(..., uint256 value) public {
             *     token.safeTransferFrom(msg.sender, address(this), value);
             *     ...
             * }
             * ```
             *
             * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
             * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
             * {SafeERC20-safeTransferFrom}).
             *
             * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
             * contracts should have entry points that don't rely on permit.
             */
            interface IERC20Permit {
                /**
                 * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
                 * given ``owner``'s signed approval.
                 *
                 * IMPORTANT: The same issues {IERC20-approve} has related to transaction
                 * ordering also apply here.
                 *
                 * Emits an {Approval} event.
                 *
                 * Requirements:
                 *
                 * - `spender` cannot be the zero address.
                 * - `deadline` must be a timestamp in the future.
                 * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
                 * over the EIP712-formatted function arguments.
                 * - the signature must use ``owner``'s current nonce (see {nonces}).
                 *
                 * For more information on the signature format, see the
                 * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
                 * section].
                 *
                 * CAUTION: See Security Considerations above.
                 */
                function permit(
                    address owner,
                    address spender,
                    uint256 value,
                    uint256 deadline,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) external;
                /**
                 * @dev Returns the current nonce for `owner`. This value must be
                 * included whenever a signature is generated for {permit}.
                 *
                 * Every successful call to {permit} increases ``owner``'s nonce by one. This
                 * prevents a signature from being used multiple times.
                 */
                function nonces(address owner) external view returns (uint256);
                /**
                 * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
                 */
                // solhint-disable-next-line func-name-mixedcase
                function DOMAIN_SEPARATOR() external view returns (bytes32);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
            pragma solidity ^0.8.0;
            import "../../interfaces/draft-IERC1822.sol";
            import "../ERC1967/ERC1967Upgrade.sol";
            /**
             * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
             * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
             *
             * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
             * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
             * `UUPSUpgradeable` with a custom implementation of upgrades.
             *
             * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
             *
             * _Available since v4.1._
             */
            abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
                /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
                address private immutable __self = address(this);
                /**
                 * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
                 * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
                 * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
                 * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
                 * fail.
                 */
                modifier onlyProxy() {
                    require(address(this) != __self, "Function must be called through delegatecall");
                    require(_getImplementation() == __self, "Function must be called through active proxy");
                    _;
                }
                /**
                 * @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, "UUPSUpgradeable: must not be called through delegatecall");
                    _;
                }
                /**
                 * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
                 * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                 *
                 * 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. This is guaranteed by the `notDelegated` modifier.
                 */
                function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
                    return _IMPLEMENTATION_SLOT;
                }
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeTo(address newImplementation) public virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
                }
                /**
                 * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                 * encoded in `data`.
                 *
                 * Calls {_authorizeUpgrade}.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                 */
                function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
                    _authorizeUpgrade(newImplementation);
                    _upgradeToAndCallUUPS(newImplementation, data, true);
                }
                /**
                 * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                 * {upgradeTo} and {upgradeToAndCall}.
                 *
                 * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                 *
                 * ```solidity
                 * function _authorizeUpgrade(address) internal override onlyOwner {}
                 * ```
                 */
                function _authorizeUpgrade(address newImplementation) internal virtual;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
            pragma solidity ^0.8.0;
            import "./OwnableUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which provides access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership} and {acceptOwnership}.
             *
             * This module is used through inheritance. It will make available all functions
             * from parent (Ownable).
             */
            abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
                address private _pendingOwner;
                event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
                function __Ownable2Step_init() internal onlyInitializing {
                    __Ownable_init_unchained();
                }
                function __Ownable2Step_init_unchained() internal onlyInitializing {
                }
                /**
                 * @dev Returns the address of the pending owner.
                 */
                function pendingOwner() public view virtual returns (address) {
                    return _pendingOwner;
                }
                /**
                 * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual override onlyOwner {
                    _pendingOwner = newOwner;
                    emit OwnershipTransferStarted(owner(), newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual override {
                    delete _pendingOwner;
                    super._transferOwnership(newOwner);
                }
                /**
                 * @dev The new owner accepts the ownership transfer.
                 */
                function acceptOwnership() public virtual {
                    address sender = _msgSender();
                    require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
                    _transferOwnership(sender);
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[49] private __gap;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            /// @title IResolver
            /// @notice This contract acts as a bridge for name-to-address resolution.
            /// @custom:security-contact [email protected]
            interface IResolver {
                error RESOLVED_TO_ZERO_ADDRESS();
                /// @notice Resolves a name to its address deployed on a specified chain.
                /// @param _chainId The chainId of interest.
                /// @param _name Name whose address is to be resolved.
                /// @param _allowZeroAddress If set to true, does not throw if the resolved
                /// address is `address(0)`.
                /// @return Address associated with the given name on the specified
                /// chain.
                function resolve(
                    uint256 _chainId,
                    bytes32 _name,
                    bool _allowZeroAddress
                )
                    external
                    view
                    returns (address);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Interface of the ERC165 standard, as defined in the
             * https://eips.ethereum.org/EIPS/eip-165[EIP].
             *
             * Implementers can declare support of contract interfaces, which can then be
             * queried by others ({ERC165Checker}).
             *
             * For an implementation, see {ERC165}.
             */
            interface IERC165 {
                /**
                 * @dev Returns true if this contract implements the interface defined by
                 * `interfaceId`. See the corresponding
                 * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                 * to learn more about how these ids are created.
                 *
                 * This function call must use less than 30 000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.24;
            library LibSharedData {
                /// @dev Struct that represents L2 basefee configurations
                struct BaseFeeConfig {
                    uint8 adjustmentQuotient;
                    uint8 sharingPctg;
                    uint32 gasIssuancePerSecond;
                    uint64 minGasExcess;
                    uint32 maxGasIssuancePerBlock;
                }
            }
            // 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.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
            pragma solidity ^0.8.2;
            import "../beacon/IBeacon.sol";
            import "../../interfaces/IERC1967.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._
             */
            abstract contract ERC1967Upgrade is IERC1967 {
                // 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 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 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 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 (last updated v4.9.0) (access/Ownable.sol)
            pragma solidity ^0.8.0;
            import "../utils/ContextUpgradeable.sol";
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
                address private _owner;
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                function __Ownable_init() internal onlyInitializing {
                    __Ownable_init_unchained();
                }
                function __Ownable_init_unchained() internal onlyInitializing {
                    _transferOwnership(_msgSender());
                }
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    _checkOwner();
                    _;
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    return _owner;
                }
                /**
                 * @dev Throws if the sender is not the owner.
                 */
                function _checkOwner() internal view virtual {
                    require(owner() == _msgSender(), "Ownable: caller is not the owner");
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby disabling any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    _transferOwnership(address(0));
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    require(newOwner != address(0), "Ownable: new owner is the zero address");
                    _transferOwnership(newOwner);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual {
                    address oldOwner = _owner;
                    _owner = newOwner;
                    emit OwnershipTransferred(oldOwner, newOwner);
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[49] private __gap;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
            pragma solidity ^0.8.2;
            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.
             *
             * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
             * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
             * case an upgrade adds a module that needs to be initialized.
             *
             * For example:
             *
             * [.hljs-theme-light.nopadding]
             * ```solidity
             * contract MyToken is ERC20Upgradeable {
             *     function initialize() initializer public {
             *         __ERC20_init("MyToken", "MTK");
             *     }
             * }
             *
             * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
             *     function initializeV2() reinitializer(2) public {
             *         __ERC20Permit_init("MyToken");
             *     }
             * }
             * ```
             *
             * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
             * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
             *
             * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
             * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
             *
             * [CAUTION]
             * ====
             * Avoid leaving a contract uninitialized.
             *
             * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
             * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
             * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
             *
             * [.hljs-theme-light.nopadding]
             * ```
             * /// @custom:oz-upgrades-unsafe-allow constructor
             * constructor() {
             *     _disableInitializers();
             * }
             * ```
             * ====
             */
            abstract contract Initializable {
                /**
                 * @dev Indicates that the contract has been initialized.
                 * @custom:oz-retyped-from bool
                 */
                uint8 private _initialized;
                /**
                 * @dev Indicates that the contract is in the process of being initialized.
                 */
                bool private _initializing;
                /**
                 * @dev Triggered when the contract has been initialized or reinitialized.
                 */
                event Initialized(uint8 version);
                /**
                 * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                 * `onlyInitializing` functions can be used to initialize parent contracts.
                 *
                 * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
                 * constructor.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier initializer() {
                    bool isTopLevelCall = !_initializing;
                    require(
                        (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                        "Initializable: contract is already initialized"
                    );
                    _initialized = 1;
                    if (isTopLevelCall) {
                        _initializing = true;
                    }
                    _;
                    if (isTopLevelCall) {
                        _initializing = false;
                        emit Initialized(1);
                    }
                }
                /**
                 * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                 * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                 * used to initialize parent contracts.
                 *
                 * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                 * are added through upgrades and that require initialization.
                 *
                 * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                 * cannot be nested. If one is invoked in the context of another, execution will revert.
                 *
                 * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                 * a contract, executing them in the right order is up to the developer or operator.
                 *
                 * WARNING: setting the version to 255 will prevent any future reinitialization.
                 *
                 * Emits an {Initialized} event.
                 */
                modifier reinitializer(uint8 version) {
                    require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                    _initialized = version;
                    _initializing = true;
                    _;
                    _initializing = false;
                    emit Initialized(version);
                }
                /**
                 * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                 * {initializer} and {reinitializer} modifiers, directly or indirectly.
                 */
                modifier onlyInitializing() {
                    require(_initializing, "Initializable: contract is not initializing");
                    _;
                }
                /**
                 * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                 * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                 * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                 * through proxies.
                 *
                 * Emits an {Initialized} event the first time it is successfully executed.
                 */
                function _disableInitializers() internal virtual {
                    require(!_initializing, "Initializable: contract is initializing");
                    if (_initialized != type(uint8).max) {
                        _initialized = type(uint8).max;
                        emit Initialized(type(uint8).max);
                    }
                }
                /**
                 * @dev Returns the highest version that has been initialized. See {reinitializer}.
                 */
                function _getInitializedVersion() internal view returns (uint8) {
                    return _initialized;
                }
                /**
                 * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                 */
                function _isInitializing() internal view returns (bool) {
                    return _initializing;
                }
            }
            // 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.9.0) (interfaces/IERC1967.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
             *
             * _Available since v4.8.3._
             */
            interface IERC1967 {
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Emitted when the beacon is changed.
                 */
                event BeaconUpgraded(address indexed beacon);
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
            // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
            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:
             * ```solidity
             * 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`, `uint256`._
             * _Available since v4.9 for `string`, `bytes`._
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                struct StringSlot {
                    string value;
                }
                struct BytesSlot {
                    bytes value;
                }
                /**
                 * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                 */
                function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                 */
                function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                 */
                function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                 */
                function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` with member `value` located at `slot`.
                 */
                function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                 */
                function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                 */
                function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                 */
                function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                    /// @solidity memory-safe-assembly
                    assembly {
                        r.slot := store.slot
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
            pragma solidity ^0.8.0;
            import {Initializable} from "../proxy/utils/Initializable.sol";
            /**
             * @dev Provides information about the current execution context, including the
             * sender of the transaction and its data. While these are generally available
             * via msg.sender and msg.data, they should not be accessed in such a direct
             * manner, since when dealing with meta-transactions the account sending and
             * paying for execution may not be the actual sender (as far as an application
             * is concerned).
             *
             * This contract is only required for intermediate, library-like contracts.
             */
            abstract contract ContextUpgradeable is Initializable {
                function __Context_init() internal onlyInitializing {
                }
                function __Context_init_unchained() internal onlyInitializing {
                }
                function _msgSender() internal view virtual returns (address) {
                    return msg.sender;
                }
                function _msgData() internal view virtual returns (bytes calldata) {
                    return msg.data;
                }
                function _contextSuffixLength() internal view virtual returns (uint256) {
                    return 0;
                }
                /**
                 * @dev This empty reserved space is put in place to allow future versions to add new
                 * variables without shifting down storage in the inheritance chain.
                 * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                 */
                uint256[50] private __gap;
            }
            // SPDX-License-Identifier: MIT
            // OpenZeppelin Contracts (last updated v4.9.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
                 *
                 * Furthermore, `isContract` will also return true if the target contract within
                 * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                 * which only has an effect at the end of a transaction.
                 * ====
                 *
                 * [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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResultFromTarget(target, 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) {
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                }
                /**
                 * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                 * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                 *
                 * _Available since v4.8._
                 */
                function verifyCallResultFromTarget(
                    address target,
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    if (success) {
                        if (returndata.length == 0) {
                            // only check isContract if the call was successful and the return data is empty
                            // otherwise we already know that it was a contract
                            require(isContract(target), "Address: call to non-contract");
                        }
                        return returndata;
                    } else {
                        _revert(returndata, errorMessage);
                    }
                }
                /**
                 * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason or 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 {
                        _revert(returndata, errorMessage);
                    }
                }
                function _revert(bytes memory returndata, string memory errorMessage) private pure {
                    // Look for revert reason and bubble it up if present
                    if (returndata.length > 0) {
                        // The easiest way to bubble the revert reason is using memory via assembly
                        /// @solidity memory-safe-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }