ETH Price: $2,649.57 (+5.21%)

Transaction Decoder

Block:
21036593 at Oct-24-2024 04:16:11 PM +UTC
Transaction Fee:
0.004465429873309548 ETH $11.83
Gas Used:
230,781 Gas / 19.349209308 Gwei

Emitted Events:

319 TransparentUpgradeableProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000da8004d6ab073b9d5549b7d5599d51ff1191c747, 0x000000000000000000000000000000000000000000000000000000000000443c )
320 TOPIAToken.Approval( owner=[Receiver] TransparentUpgradeableProxy, spender=TransparentUpgradeableProxy, value=2001000000000000000 )
321 TOPIAToken.Approval( owner=[Receiver] TransparentUpgradeableProxy, spender=TransparentUpgradeableProxy, value=0 )
322 TOPIAToken.Transfer( from=[Receiver] TransparentUpgradeableProxy, to=TransparentUpgradeableProxy, value=2001000000000000000 )
323 TransparentUpgradeableProxy.0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1( 0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1, 0x0000000000000000000000000000000000000000000000000000000000001f27, 0x15c60bd0db4cbb24bc986484843da0dcd24c77f97a21688d94cfa6f39787c409, 000000000000000000000000d6c596b7ca17870dd50d322393dece6c2085a116, 0000000000000000000000000000000000000000000000000000000000000009, 000000000000000000000000c51ddd7599d8f52c48f29e10cfbf24918c8608dd, 420ad51967a3a78c4e7841777756ed331c33885d83bfdf7e95816e4835a80599, 0000000000000000000000000000000000000000000000000000000000000000, 00000000000000000000000000000000000000000000000000000000671a72cb )
324 TOPIAToken.Transfer( from=TransparentUpgradeableProxy, to=TransparentUpgradeableProxy, value=2001000000000000000 )
325 TransparentUpgradeableProxy.0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b( 0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b, 0x0000000000000000000000000000000000000000000000000000000000001f27, 0000000000000000000000000000000000000000000000000000000000000020, 0000000000000000000000000000000000000000000000000000000000000184, 000000000000000000000000e1060b30d9ff01eef71248906ce802801a670a48, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000001bc4fae5f38e8000, 0000000000000000000000000000000000000000000000000000000001312d00, 000000000000000000000000e1060b30d9ff01eef71248906ce802801a670a48, 000000000000000000000000e1060b30d9ff01eef71248906ce802801a670a48, 00000000000000000000000000000000000000000000000000000000000f4240, 000000000000000000000000000000000000000000000000000001d1a94a2000, 0000000000000000000000000000000000000000000000000000000000000064, 156e29f6000000000000000000000000da8004d6ab073b9d5549b7d5599d51ff, 1191c74700000000000000000000000000000000000000000000000000000000, 0000443c00000000000000000000000000000000000000000000000000000000, 0000000100000000000000000000000000000000000000000000000000000000 )
326 TransparentUpgradeableProxy.0xca2f3369226bd2e9158ce725ecd9c8fb32cd8b15b4caf9cd444a115c67574c2f( 0xca2f3369226bd2e9158ce725ecd9c8fb32cd8b15b4caf9cd444a115c67574c2f, 0x000000000000000000000000da8004d6ab073b9d5549b7d5599d51ff1191c747, 0x0000000000000000000000000000000000000000000000000000000000001f27, 000000000000000000000000000000000000000000000000000000000000443c, 0000000000000000000000000000000000000000000000000000000000000001 )

Account State Difference:

  Address   Before After State Difference Code
0x73C6af70...35011Da68
(beaverbuild)
11.151833326188417279 Eth11.152169112543417279 Eth0.000335786355
0xB40cdD75...18C85F7cC 1.81343904 Eth2.04474504 Eth0.231306
0xcccCb68e...143ed40C3
0xDA8004D6...F1191C747
0.336066362986230465 Eth
Nonce: 25
0.100294933112920917 Eth
Nonce: 26
0.235771429873309548

Execution Trace

ETH 0.266002 TransparentUpgradeableProxy.40c10f19( )
  • ETH 0.266002 0x91fffdfcab5123ddb895f05487e25cc3d447bbd5.40c10f19( )
    • ETH 0.034696 0xda8004d6ab073b9d5549b7d5599d51ff1191c747.CALL( )
    • TOPIAToken.balanceOf( account=0xB40cdD7599d8f52C48f29E10CFBf24918C85F7cC ) => ( 48454056000000000000000 )
    • TOPIAToken.approve( spender=0xD6c596b7ca17870DD50D322393deCE6C2085a116, amount=2001000000000000000 ) => ( True )
    • TransparentUpgradeableProxy.549e8426( )
      • ERC20Inbox.createRetryableTicket( to=0xE1060b30D9fF01Eef71248906Ce802801a670A48, l2CallValue=0, maxSubmissionCost=20000000, excessFeeRefundAddress=0xE1060b30D9fF01Eef71248906Ce802801a670A48, callValueRefundAddress=0xE1060b30D9fF01Eef71248906Ce802801a670A48, gasLimit=1000000, maxFeePerGas=2000000000000, tokenTotalFeeAmount=2001000000000000000, data=0x156E29F6000000000000000000000000DA8004D6AB073B9D5549B7D5599D51FF1191C747000000000000000000000000000000000000000000000000000000000000443C0000000000000000000000000000000000000000000000000000000000000001 ) => ( 7975 )
        • TransparentUpgradeableProxy.STATICCALL( )
          • ERC20Bridge.DELEGATECALL( )
          • TOPIAToken.balanceOf( account=0xD6c596b7ca17870DD50D322393deCE6C2085a116 ) => ( 0 )
          • TOPIAToken.transferFrom( from=0xB40cdD7599d8f52C48f29E10CFBf24918C85F7cC, to=0xD6c596b7ca17870DD50D322393deCE6C2085a116, amount=2001000000000000000 ) => ( True )
          • TransparentUpgradeableProxy.75d81e25( )
            • ERC20Bridge.enqueueDelayedMessage( kind=9, sender=0xc51dDD7599d8f52c48F29e10cFBF24918c8608dd, messageDataHash=420AD51967A3A78C4E7841777756ED331C33885D83BFDF7E95816E4835A80599, tokenFeeAmount=2001000000000000000 ) => ( 7975 )
              • TOPIAToken.transferFrom( from=0xD6c596b7ca17870DD50D322393deCE6C2085a116, to=0x73C6af7029E714DFf1F1554F88b79B335011Da68, amount=2001000000000000000 ) => ( True )
                File 1 of 6: TransparentUpgradeableProxy
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0-rc.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 v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)
                pragma solidity ^0.8.0;
                import "../Proxy.sol";
                import "./ERC1967Upgrade.sol";
                /**
                 * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                 * implementation address that can be changed. This address is stored in storage in the location specified by
                 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                 * implementation behind the proxy.
                 */
                contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                    /**
                     * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                     *
                     * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                     * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                     */
                    constructor(address _logic, bytes memory _data) payable {
                        assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                        _upgradeToAndCall(_logic, _data, false);
                    }
                    /**
                     * @dev Returns the current implementation address.
                     */
                    function _implementation() internal view virtual override returns (address impl) {
                        return ERC1967Upgrade._getImplementation();
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0-rc.0) (proxy/ERC1967/ERC1967Upgrade.sol)
                pragma solidity ^0.8.2;
                import "../beacon/IBeacon.sol";
                import "../../interfaces/draft-IERC1822.sol";
                import "../../utils/Address.sol";
                import "../../utils/StorageSlot.sol";
                /**
                 * @dev This abstract contract provides getters and event emitting update functions for
                 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                 *
                 * _Available since v4.1._
                 *
                 * @custom:oz-upgrades-unsafe-allow delegatecall
                 */
                abstract contract ERC1967Upgrade {
                    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                    /**
                     * @dev Storage slot with the address of the current implementation.
                     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                     * validated in the constructor.
                     */
                    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                    /**
                     * @dev Emitted when the implementation is upgraded.
                     */
                    event Upgraded(address indexed implementation);
                    /**
                     * @dev Returns the current implementation address.
                     */
                    function _getImplementation() internal view returns (address) {
                        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                    }
                    /**
                     * @dev Stores a new address in the EIP1967 implementation slot.
                     */
                    function _setImplementation(address newImplementation) private {
                        require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                    }
                    /**
                     * @dev Perform implementation upgrade
                     *
                     * Emits an {Upgraded} event.
                     */
                    function _upgradeTo(address newImplementation) internal {
                        _setImplementation(newImplementation);
                        emit Upgraded(newImplementation);
                    }
                    /**
                     * @dev Perform implementation upgrade with additional setup call.
                     *
                     * Emits an {Upgraded} event.
                     */
                    function _upgradeToAndCall(
                        address newImplementation,
                        bytes memory data,
                        bool forceCall
                    ) internal {
                        _upgradeTo(newImplementation);
                        if (data.length > 0 || forceCall) {
                            Address.functionDelegateCall(newImplementation, data);
                        }
                    }
                    /**
                     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                     *
                     * Emits an {Upgraded} event.
                     */
                    function _upgradeToAndCallUUPS(
                        address newImplementation,
                        bytes memory data,
                        bool forceCall
                    ) internal {
                        // Upgrades from old implementations will perform a rollback test. This test requires the new
                        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                        // this special case will break upgrade paths from old UUPS implementation to new ones.
                        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
                            _setImplementation(newImplementation);
                        } else {
                            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                            } catch {
                                revert("ERC1967Upgrade: new implementation is not UUPS");
                            }
                            _upgradeToAndCall(newImplementation, data, forceCall);
                        }
                    }
                    /**
                     * @dev Storage slot with the admin of the contract.
                     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                     * validated in the constructor.
                     */
                    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                    /**
                     * @dev Emitted when the admin account has changed.
                     */
                    event AdminChanged(address previousAdmin, address newAdmin);
                    /**
                     * @dev Returns the current admin.
                     */
                    function _getAdmin() internal view virtual returns (address) {
                        return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                    }
                    /**
                     * @dev Stores a new address in the EIP1967 admin slot.
                     */
                    function _setAdmin(address newAdmin) private {
                        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                    }
                    /**
                     * @dev Changes the admin of the proxy.
                     *
                     * Emits an {AdminChanged} event.
                     */
                    function _changeAdmin(address newAdmin) internal {
                        emit AdminChanged(_getAdmin(), newAdmin);
                        _setAdmin(newAdmin);
                    }
                    /**
                     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                     */
                    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                    /**
                     * @dev Emitted when the beacon is upgraded.
                     */
                    event BeaconUpgraded(address indexed beacon);
                    /**
                     * @dev Returns the current beacon.
                     */
                    function _getBeacon() internal view returns (address) {
                        return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                    }
                    /**
                     * @dev Stores a new beacon in the EIP1967 beacon slot.
                     */
                    function _setBeacon(address newBeacon) private {
                        require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                        require(Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract");
                        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                    }
                    /**
                     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                     *
                     * Emits a {BeaconUpgraded} event.
                     */
                    function _upgradeBeaconToAndCall(
                        address newBeacon,
                        bytes memory data,
                        bool forceCall
                    ) internal {
                        _setBeacon(newBeacon);
                        emit BeaconUpgraded(newBeacon);
                        if (data.length > 0 || forceCall) {
                            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0-rc.0) (proxy/Proxy.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                 * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                 * be specified by overriding the virtual {_implementation} function.
                 *
                 * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                 * different contract through the {_delegate} function.
                 *
                 * The success and return data of the delegated call will be returned back to the caller of the proxy.
                 */
                abstract contract Proxy {
                    /**
                     * @dev Delegates the current call to `implementation`.
                     *
                     * This function does not return to its internal call site, it will return directly to the external caller.
                     */
                    function _delegate(address implementation) internal virtual {
                        assembly {
                            // Copy msg.data. We take full control of memory in this inline assembly
                            // block because it will not return to Solidity code. We overwrite the
                            // Solidity scratch pad at memory position 0.
                            calldatacopy(0, 0, calldatasize())
                            // Call the implementation.
                            // out and outsize are 0 because we don't know the size yet.
                            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                            // Copy the returned data.
                            returndatacopy(0, 0, returndatasize())
                            switch result
                            // delegatecall returns 0 on error.
                            case 0 {
                                revert(0, returndatasize())
                            }
                            default {
                                return(0, returndatasize())
                            }
                        }
                    }
                    /**
                     * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                     * and {_fallback} should delegate.
                     */
                    function _implementation() internal view virtual returns (address);
                    /**
                     * @dev Delegates the current call to the address returned by `_implementation()`.
                     *
                     * This function does not return to its internall call site, it will return directly to the external caller.
                     */
                    function _fallback() internal virtual {
                        _beforeFallback();
                        _delegate(_implementation());
                    }
                    /**
                     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                     * function in the contract matches the call data.
                     */
                    fallback() external payable virtual {
                        _fallback();
                    }
                    /**
                     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                     * is empty.
                     */
                    receive() external payable virtual {
                        _fallback();
                    }
                    /**
                     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                     * call, or as part of the Solidity `fallback` or `receive` functions.
                     *
                     * If overriden should call `super._beforeFallback()`.
                     */
                    function _beforeFallback() internal virtual {}
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts 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 v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)
                pragma solidity ^0.8.0;
                import "../ERC1967/ERC1967Proxy.sol";
                /**
                 * @dev This contract implements a proxy that is upgradeable by an admin.
                 *
                 * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
                 * clashing], which can potentially be used in an attack, this contract uses the
                 * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
                 * things that go hand in hand:
                 *
                 * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
                 * that call matches one of the admin functions exposed by the proxy itself.
                 * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
                 * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
                 * "admin cannot fallback to proxy target".
                 *
                 * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
                 * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
                 * to sudden errors when trying to call a function from the proxy implementation.
                 *
                 * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
                 * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
                 */
                contract TransparentUpgradeableProxy is ERC1967Proxy {
                    /**
                     * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                     * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                     */
                    constructor(
                        address _logic,
                        address admin_,
                        bytes memory _data
                    ) payable ERC1967Proxy(_logic, _data) {
                        assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                        _changeAdmin(admin_);
                    }
                    /**
                     * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                     */
                    modifier ifAdmin() {
                        if (msg.sender == _getAdmin()) {
                            _;
                        } else {
                            _fallback();
                        }
                    }
                    /**
                     * @dev Returns the current admin.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                     *
                     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                     * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                     * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                     */
                    function admin() external ifAdmin returns (address admin_) {
                        admin_ = _getAdmin();
                    }
                    /**
                     * @dev Returns the current implementation.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                     *
                     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                     * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                     * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                     */
                    function implementation() external ifAdmin returns (address implementation_) {
                        implementation_ = _implementation();
                    }
                    /**
                     * @dev Changes the admin of the proxy.
                     *
                     * Emits an {AdminChanged} event.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                     */
                    function changeAdmin(address newAdmin) external virtual ifAdmin {
                        _changeAdmin(newAdmin);
                    }
                    /**
                     * @dev Upgrade the implementation of the proxy.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                     */
                    function upgradeTo(address newImplementation) external ifAdmin {
                        _upgradeToAndCall(newImplementation, bytes(""), false);
                    }
                    /**
                     * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                     * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                     * proxied contract.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                     */
                    function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                        _upgradeToAndCall(newImplementation, data, true);
                    }
                    /**
                     * @dev Returns the current admin.
                     */
                    function _admin() internal view virtual returns (address) {
                        return _getAdmin();
                    }
                    /**
                     * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                     */
                    function _beforeFallback() internal virtual override {
                        require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                        super._beforeFallback();
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)
                pragma solidity ^0.8.1;
                /**
                 * @dev Collection of functions related to the address type
                 */
                library Address {
                    /**
                     * @dev Returns true if `account` is a contract.
                     *
                     * [IMPORTANT]
                     * ====
                     * It is unsafe to assume that an address for which this function returns
                     * false is an externally-owned account (EOA) and not a contract.
                     *
                     * Among others, `isContract` will return false for the following
                     * types of addresses:
                     *
                     *  - an externally-owned account
                     *  - a contract in construction
                     *  - an address where a contract will be created
                     *  - an address where a contract lived, but was destroyed
                     * ====
                     *
                     * [IMPORTANT]
                     * ====
                     * You shouldn't rely on `isContract` to protect against flash loan attacks!
                     *
                     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                     * constructor.
                     * ====
                     */
                    function isContract(address account) internal view returns (bool) {
                        // This method relies on extcodesize/address.code.length, which returns 0
                        // for contracts in construction, since the code is only stored at the end
                        // of the constructor execution.
                        return account.code.length > 0;
                    }
                    /**
                     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                     * `recipient`, forwarding all available gas and reverting on errors.
                     *
                     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                     * of certain opcodes, possibly making contracts go over the 2300 gas limit
                     * imposed by `transfer`, making them unable to receive funds via
                     * `transfer`. {sendValue} removes this limitation.
                     *
                     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                     *
                     * IMPORTANT: because control is transferred to `recipient`, care must be
                     * taken to not create reentrancy vulnerabilities. Consider using
                     * {ReentrancyGuard} or the
                     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                     */
                    function sendValue(address payable recipient, uint256 amount) internal {
                        require(address(this).balance >= amount, "Address: insufficient balance");
                        (bool success, ) = recipient.call{value: amount}("");
                        require(success, "Address: unable to send value, recipient may have reverted");
                    }
                    /**
                     * @dev Performs a Solidity function call using a low level `call`. A
                     * plain `call` is an unsafe replacement for a function call: use this
                     * function instead.
                     *
                     * If `target` reverts with a revert reason, it is bubbled up by this
                     * function (like regular Solidity function calls).
                     *
                     * Returns the raw returned data. To convert to the expected return value,
                     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                     *
                     * Requirements:
                     *
                     * - `target` must be a contract.
                     * - calling `target` with `data` must not revert.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionCall(target, data, "Address: low-level call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                     * `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, 0, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but also transferring `value` wei to `target`.
                     *
                     * Requirements:
                     *
                     * - the calling contract must have an ETH balance of at least `value`.
                     * - the called Solidity function must be `payable`.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                     * with `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(address(this).balance >= value, "Address: insufficient balance for call");
                        require(isContract(target), "Address: call to non-contract");
                        (bool success, bytes memory returndata) = target.call{value: value}(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                        return functionStaticCall(target, data, "Address: low-level static call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal view returns (bytes memory) {
                        require(isContract(target), "Address: static call to non-contract");
                        (bool success, bytes memory returndata) = target.staticcall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a delegate call.
                     *
                     * _Available since v3.4._
                     */
                    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a delegate call.
                     *
                     * _Available since v3.4._
                     */
                    function functionDelegateCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(isContract(target), "Address: delegate call to non-contract");
                        (bool success, bytes memory returndata) = target.delegatecall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                     * revert reason using the provided one.
                     *
                     * _Available since v4.3._
                     */
                    function verifyCallResult(
                        bool success,
                        bytes memory returndata,
                        string memory errorMessage
                    ) internal pure returns (bytes memory) {
                        if (success) {
                            return returndata;
                        } else {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert(errorMessage);
                            }
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev Library for reading and writing primitive types to specific storage slots.
                 *
                 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                 * This library helps with reading and writing to such slots without the need for inline assembly.
                 *
                 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                 *
                 * Example usage to set ERC1967 implementation slot:
                 * ```
                 * contract ERC1967 {
                 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                 *
                 *     function _getImplementation() internal view returns (address) {
                 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                 *     }
                 *
                 *     function _setImplementation(address newImplementation) internal {
                 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                 *     }
                 * }
                 * ```
                 *
                 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                 */
                library StorageSlot {
                    struct AddressSlot {
                        address value;
                    }
                    struct BooleanSlot {
                        bool value;
                    }
                    struct Bytes32Slot {
                        bytes32 value;
                    }
                    struct Uint256Slot {
                        uint256 value;
                    }
                    /**
                     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                     */
                    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                     */
                    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                     */
                    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                     */
                    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                }
                

                File 2 of 6: TOPIAToken
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
                pragma solidity ^0.8.0;
                import "../utils/Context.sol";
                /**
                 * @dev Contract module which provides a basic access control mechanism, where
                 * there is an account (an owner) that can be granted exclusive access to
                 * specific functions.
                 *
                 * By default, the owner account will be the one that deploys the contract. This
                 * can later be changed with {transferOwnership}.
                 *
                 * This module is used through inheritance. It will make available the modifier
                 * `onlyOwner`, which can be applied to your functions to restrict their use to
                 * the owner.
                 */
                abstract contract Ownable is Context {
                    address private _owner;
                    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                    /**
                     * @dev Initializes the contract setting the deployer as the initial owner.
                     */
                    constructor() {
                        _transferOwnership(_msgSender());
                    }
                    /**
                     * @dev Throws if called by any account other than the owner.
                     */
                    modifier onlyOwner() {
                        _checkOwner();
                        _;
                    }
                    /**
                     * @dev Returns the address of the current owner.
                     */
                    function owner() public view virtual returns (address) {
                        return _owner;
                    }
                    /**
                     * @dev Throws if the sender is not the owner.
                     */
                    function _checkOwner() internal view virtual {
                        require(owner() == _msgSender(), "Ownable: caller is not the owner");
                    }
                    /**
                     * @dev Leaves the contract without owner. It will not be possible to call
                     * `onlyOwner` functions anymore. Can only be called by the current owner.
                     *
                     * NOTE: Renouncing ownership will leave the contract without an owner,
                     * thereby removing any functionality that is only available to the owner.
                     */
                    function renounceOwnership() public virtual onlyOwner {
                        _transferOwnership(address(0));
                    }
                    /**
                     * @dev Transfers ownership of the contract to a new account (`newOwner`).
                     * Can only be called by the current owner.
                     */
                    function transferOwnership(address newOwner) public virtual onlyOwner {
                        require(newOwner != address(0), "Ownable: new owner is the zero address");
                        _transferOwnership(newOwner);
                    }
                    /**
                     * @dev Transfers ownership of the contract to a new account (`newOwner`).
                     * Internal function without access restriction.
                     */
                    function _transferOwnership(address newOwner) internal virtual {
                        address oldOwner = _owner;
                        _owner = newOwner;
                        emit OwnershipTransferred(oldOwner, newOwner);
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
                pragma solidity ^0.8.0;
                import "./IERC20.sol";
                import "./extensions/IERC20Metadata.sol";
                import "../../utils/Context.sol";
                /**
                 * @dev Implementation of the {IERC20} interface.
                 *
                 * This implementation is agnostic to the way tokens are created. This means
                 * that a supply mechanism has to be added in a derived contract using {_mint}.
                 * For a generic mechanism see {ERC20PresetMinterPauser}.
                 *
                 * TIP: For a detailed writeup see our guide
                 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
                 * to implement supply mechanisms].
                 *
                 * We have followed general OpenZeppelin Contracts guidelines: functions revert
                 * instead returning `false` on failure. This behavior is nonetheless
                 * conventional and does not conflict with the expectations of ERC20
                 * applications.
                 *
                 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
                 * This allows applications to reconstruct the allowance for all accounts just
                 * by listening to said events. Other implementations of the EIP may not emit
                 * these events, as it isn't required by the specification.
                 *
                 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
                 * functions have been added to mitigate the well-known issues around setting
                 * allowances. See {IERC20-approve}.
                 */
                contract ERC20 is Context, IERC20, IERC20Metadata {
                    mapping(address => uint256) private _balances;
                    mapping(address => mapping(address => uint256)) private _allowances;
                    uint256 private _totalSupply;
                    string private _name;
                    string private _symbol;
                    /**
                     * @dev Sets the values for {name} and {symbol}.
                     *
                     * The default value of {decimals} is 18. To select a different value for
                     * {decimals} you should overload it.
                     *
                     * All two of these values are immutable: they can only be set once during
                     * construction.
                     */
                    constructor(string memory name_, string memory symbol_) {
                        _name = name_;
                        _symbol = symbol_;
                    }
                    /**
                     * @dev Returns the name of the token.
                     */
                    function name() public view virtual override returns (string memory) {
                        return _name;
                    }
                    /**
                     * @dev Returns the symbol of the token, usually a shorter version of the
                     * name.
                     */
                    function symbol() public view virtual override returns (string memory) {
                        return _symbol;
                    }
                    /**
                     * @dev Returns the number of decimals used to get its user representation.
                     * For example, if `decimals` equals `2`, a balance of `505` tokens should
                     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
                     *
                     * Tokens usually opt for a value of 18, imitating the relationship between
                     * Ether and Wei. This is the value {ERC20} uses, unless this function is
                     * overridden;
                     *
                     * NOTE: This information is only used for _display_ purposes: it in
                     * no way affects any of the arithmetic of the contract, including
                     * {IERC20-balanceOf} and {IERC20-transfer}.
                     */
                    function decimals() public view virtual override returns (uint8) {
                        return 18;
                    }
                    /**
                     * @dev See {IERC20-totalSupply}.
                     */
                    function totalSupply() public view virtual override returns (uint256) {
                        return _totalSupply;
                    }
                    /**
                     * @dev See {IERC20-balanceOf}.
                     */
                    function balanceOf(address account) public view virtual override returns (uint256) {
                        return _balances[account];
                    }
                    /**
                     * @dev See {IERC20-transfer}.
                     *
                     * Requirements:
                     *
                     * - `to` cannot be the zero address.
                     * - the caller must have a balance of at least `amount`.
                     */
                    function transfer(address to, uint256 amount) public virtual override returns (bool) {
                        address owner = _msgSender();
                        _transfer(owner, to, amount);
                        return true;
                    }
                    /**
                     * @dev See {IERC20-allowance}.
                     */
                    function allowance(address owner, address spender) public view virtual override returns (uint256) {
                        return _allowances[owner][spender];
                    }
                    /**
                     * @dev See {IERC20-approve}.
                     *
                     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
                     * `transferFrom`. This is semantically equivalent to an infinite approval.
                     *
                     * Requirements:
                     *
                     * - `spender` cannot be the zero address.
                     */
                    function approve(address spender, uint256 amount) public virtual override returns (bool) {
                        address owner = _msgSender();
                        _approve(owner, spender, amount);
                        return true;
                    }
                    /**
                     * @dev See {IERC20-transferFrom}.
                     *
                     * Emits an {Approval} event indicating the updated allowance. This is not
                     * required by the EIP. See the note at the beginning of {ERC20}.
                     *
                     * NOTE: Does not update the allowance if the current allowance
                     * is the maximum `uint256`.
                     *
                     * Requirements:
                     *
                     * - `from` and `to` cannot be the zero address.
                     * - `from` must have a balance of at least `amount`.
                     * - the caller must have allowance for ``from``'s tokens of at least
                     * `amount`.
                     */
                    function transferFrom(
                        address from,
                        address to,
                        uint256 amount
                    ) public virtual override returns (bool) {
                        address spender = _msgSender();
                        _spendAllowance(from, spender, amount);
                        _transfer(from, to, amount);
                        return true;
                    }
                    /**
                     * @dev Atomically increases the allowance granted to `spender` by the caller.
                     *
                     * This is an alternative to {approve} that can be used as a mitigation for
                     * problems described in {IERC20-approve}.
                     *
                     * Emits an {Approval} event indicating the updated allowance.
                     *
                     * Requirements:
                     *
                     * - `spender` cannot be the zero address.
                     */
                    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                        address owner = _msgSender();
                        _approve(owner, spender, allowance(owner, spender) + addedValue);
                        return true;
                    }
                    /**
                     * @dev Atomically decreases the allowance granted to `spender` by the caller.
                     *
                     * This is an alternative to {approve} that can be used as a mitigation for
                     * problems described in {IERC20-approve}.
                     *
                     * Emits an {Approval} event indicating the updated allowance.
                     *
                     * Requirements:
                     *
                     * - `spender` cannot be the zero address.
                     * - `spender` must have allowance for the caller of at least
                     * `subtractedValue`.
                     */
                    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                        address owner = _msgSender();
                        uint256 currentAllowance = allowance(owner, spender);
                        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
                        unchecked {
                            _approve(owner, spender, currentAllowance - subtractedValue);
                        }
                        return true;
                    }
                    /**
                     * @dev Moves `amount` of tokens from `from` to `to`.
                     *
                     * This internal function is equivalent to {transfer}, and can be used to
                     * e.g. implement automatic token fees, slashing mechanisms, etc.
                     *
                     * Emits a {Transfer} event.
                     *
                     * Requirements:
                     *
                     * - `from` cannot be the zero address.
                     * - `to` cannot be the zero address.
                     * - `from` must have a balance of at least `amount`.
                     */
                    function _transfer(
                        address from,
                        address to,
                        uint256 amount
                    ) internal virtual {
                        require(from != address(0), "ERC20: transfer from the zero address");
                        require(to != address(0), "ERC20: transfer to the zero address");
                        _beforeTokenTransfer(from, to, amount);
                        uint256 fromBalance = _balances[from];
                        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
                        unchecked {
                            _balances[from] = fromBalance - amount;
                            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
                            // decrementing then incrementing.
                            _balances[to] += amount;
                        }
                        emit Transfer(from, to, amount);
                        _afterTokenTransfer(from, to, amount);
                    }
                    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                     * the total supply.
                     *
                     * Emits a {Transfer} event with `from` set to the zero address.
                     *
                     * Requirements:
                     *
                     * - `account` cannot be the zero address.
                     */
                    function _mint(address account, uint256 amount) internal virtual {
                        require(account != address(0), "ERC20: mint to the zero address");
                        _beforeTokenTransfer(address(0), account, amount);
                        _totalSupply += amount;
                        unchecked {
                            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
                            _balances[account] += amount;
                        }
                        emit Transfer(address(0), account, amount);
                        _afterTokenTransfer(address(0), account, amount);
                    }
                    /**
                     * @dev Destroys `amount` tokens from `account`, reducing the
                     * total supply.
                     *
                     * Emits a {Transfer} event with `to` set to the zero address.
                     *
                     * Requirements:
                     *
                     * - `account` cannot be the zero address.
                     * - `account` must have at least `amount` tokens.
                     */
                    function _burn(address account, uint256 amount) internal virtual {
                        require(account != address(0), "ERC20: burn from the zero address");
                        _beforeTokenTransfer(account, address(0), amount);
                        uint256 accountBalance = _balances[account];
                        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
                        unchecked {
                            _balances[account] = accountBalance - amount;
                            // Overflow not possible: amount <= accountBalance <= totalSupply.
                            _totalSupply -= amount;
                        }
                        emit Transfer(account, address(0), amount);
                        _afterTokenTransfer(account, address(0), amount);
                    }
                    /**
                     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                     *
                     * This internal function is equivalent to `approve`, and can be used to
                     * e.g. set automatic allowances for certain subsystems, etc.
                     *
                     * Emits an {Approval} event.
                     *
                     * Requirements:
                     *
                     * - `owner` cannot be the zero address.
                     * - `spender` cannot be the zero address.
                     */
                    function _approve(
                        address owner,
                        address spender,
                        uint256 amount
                    ) internal virtual {
                        require(owner != address(0), "ERC20: approve from the zero address");
                        require(spender != address(0), "ERC20: approve to the zero address");
                        _allowances[owner][spender] = amount;
                        emit Approval(owner, spender, amount);
                    }
                    /**
                     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
                     *
                     * Does not update the allowance amount in case of infinite allowance.
                     * Revert if not enough allowance is available.
                     *
                     * Might emit an {Approval} event.
                     */
                    function _spendAllowance(
                        address owner,
                        address spender,
                        uint256 amount
                    ) internal virtual {
                        uint256 currentAllowance = allowance(owner, spender);
                        if (currentAllowance != type(uint256).max) {
                            require(currentAllowance >= amount, "ERC20: insufficient allowance");
                            unchecked {
                                _approve(owner, spender, currentAllowance - amount);
                            }
                        }
                    }
                    /**
                     * @dev Hook that is called before any transfer of tokens. This includes
                     * minting and burning.
                     *
                     * Calling conditions:
                     *
                     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                     * will be transferred to `to`.
                     * - when `from` is zero, `amount` tokens will be minted for `to`.
                     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                     * - `from` and `to` are never both zero.
                     *
                     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                     */
                    function _beforeTokenTransfer(
                        address from,
                        address to,
                        uint256 amount
                    ) internal virtual {}
                    /**
                     * @dev Hook that is called after any transfer of tokens. This includes
                     * minting and burning.
                     *
                     * Calling conditions:
                     *
                     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                     * has been transferred to `to`.
                     * - when `from` is zero, `amount` tokens have been minted for `to`.
                     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
                     * - `from` and `to` are never both zero.
                     *
                     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                     */
                    function _afterTokenTransfer(
                        address from,
                        address to,
                        uint256 amount
                    ) internal virtual {}
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Capped.sol)
                pragma solidity ^0.8.0;
                import "../ERC20.sol";
                /**
                 * @dev Extension of {ERC20} that adds a cap to the supply of tokens.
                 */
                abstract contract ERC20Capped is ERC20 {
                    uint256 private immutable _cap;
                    /**
                     * @dev Sets the value of the `cap`. This value is immutable, it can only be
                     * set once during construction.
                     */
                    constructor(uint256 cap_) {
                        require(cap_ > 0, "ERC20Capped: cap is 0");
                        _cap = cap_;
                    }
                    /**
                     * @dev Returns the cap on the token's total supply.
                     */
                    function cap() public view virtual returns (uint256) {
                        return _cap;
                    }
                    /**
                     * @dev See {ERC20-_mint}.
                     */
                    function _mint(address account, uint256 amount) internal virtual override {
                        require(ERC20.totalSupply() + amount <= cap(), "ERC20Capped: cap exceeded");
                        super._mint(account, amount);
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
                pragma solidity ^0.8.0;
                import "../IERC20.sol";
                /**
                 * @dev Interface for the optional metadata functions from the ERC20 standard.
                 *
                 * _Available since v4.1._
                 */
                interface IERC20Metadata is IERC20 {
                    /**
                     * @dev Returns the name of the token.
                     */
                    function name() external view returns (string memory);
                    /**
                     * @dev Returns the symbol of the token.
                     */
                    function symbol() external view returns (string memory);
                    /**
                     * @dev Returns the decimals places of the token.
                     */
                    function decimals() external view returns (uint8);
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.6.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 v4.4.1 (utils/Context.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev Provides information about the current execution context, including the
                 * sender of the transaction and its data. While these are generally available
                 * via msg.sender and msg.data, they should not be accessed in such a direct
                 * manner, since when dealing with meta-transactions the account sending and
                 * paying for execution may not be the actual sender (as far as an application
                 * is concerned).
                 *
                 * This contract is only required for intermediate, library-like contracts.
                 */
                abstract contract Context {
                    function _msgSender() internal view virtual returns (address) {
                        return msg.sender;
                    }
                    function _msgData() internal view virtual returns (bytes calldata) {
                        return msg.data;
                    }
                }
                // SPDX-License-Identifier: MIT
                //
                // ...............   ...............   ...............  .....   ...............
                // :==============.  ===============  :==============:  -====  .==============-
                // :==============.  ===============  :==============:  -====  .==============-
                // :==============.  ===============  :==============:  -====  .==============-
                // :==============.  ===============  :==============:  -====  .==============-
                // .::::-====-::::.  ===============  :====-:::::::::.  -====  .====-::::-====-
                //      :====.       ===============  :====:            -====  .====:    .====-
                //      :====.       ===============  :====:            -====  .====:    .====-
                //
                // Learn more at https://topia.gg or Twitter @TOPIAgg
                pragma solidity 0.8.18;
                import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
                import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol";
                import "@openzeppelin/contracts/access/Ownable.sol";
                contract TOPIAToken is ERC20, ERC20Capped, Ownable {
                  constructor()
                  ERC20("TOPIA", "TOPIA")
                  ERC20Capped(5000000000 ether) {}
                  function mint(address _to, uint256 _amount) external onlyOwner {
                    _mint(_to, _amount);
                  }
                  /**
                   * Overrides
                   */
                  function _mint(address _to, uint256 _amount) internal override(ERC20, ERC20Capped) {
                    super._mint(_to, _amount);
                  }
                }
                

                File 3 of 6: TransparentUpgradeableProxy
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)
                pragma solidity ^0.8.0;
                import "../ERC1967/ERC1967Proxy.sol";
                /**
                 * @dev This contract implements a proxy that is upgradeable by an admin.
                 *
                 * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
                 * clashing], which can potentially be used in an attack, this contract uses the
                 * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
                 * things that go hand in hand:
                 *
                 * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
                 * that call matches one of the admin functions exposed by the proxy itself.
                 * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
                 * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
                 * "admin cannot fallback to proxy target".
                 *
                 * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
                 * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
                 * to sudden errors when trying to call a function from the proxy implementation.
                 *
                 * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
                 * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
                 */
                contract TransparentUpgradeableProxy is ERC1967Proxy {
                    /**
                     * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                     * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                     */
                    constructor(
                        address _logic,
                        address admin_,
                        bytes memory _data
                    ) payable ERC1967Proxy(_logic, _data) {
                        assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                        _changeAdmin(admin_);
                    }
                    /**
                     * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                     */
                    modifier ifAdmin() {
                        if (msg.sender == _getAdmin()) {
                            _;
                        } else {
                            _fallback();
                        }
                    }
                    /**
                     * @dev Returns the current admin.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                     *
                     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                     * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                     * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                     */
                    function admin() external ifAdmin returns (address admin_) {
                        admin_ = _getAdmin();
                    }
                    /**
                     * @dev Returns the current implementation.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                     *
                     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                     * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                     * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                     */
                    function implementation() external ifAdmin returns (address implementation_) {
                        implementation_ = _implementation();
                    }
                    /**
                     * @dev Changes the admin of the proxy.
                     *
                     * Emits an {AdminChanged} event.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                     */
                    function changeAdmin(address newAdmin) external virtual ifAdmin {
                        _changeAdmin(newAdmin);
                    }
                    /**
                     * @dev Upgrade the implementation of the proxy.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                     */
                    function upgradeTo(address newImplementation) external ifAdmin {
                        _upgradeToAndCall(newImplementation, bytes(""), false);
                    }
                    /**
                     * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                     * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                     * proxied contract.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                     */
                    function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                        _upgradeToAndCall(newImplementation, data, true);
                    }
                    /**
                     * @dev Returns the current admin.
                     */
                    function _admin() internal view virtual returns (address) {
                        return _getAdmin();
                    }
                    /**
                     * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                     */
                    function _beforeFallback() internal virtual override {
                        require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                        super._beforeFallback();
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)
                pragma solidity ^0.8.0;
                import "../Proxy.sol";
                import "./ERC1967Upgrade.sol";
                /**
                 * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                 * implementation address that can be changed. This address is stored in storage in the location specified by
                 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                 * implementation behind the proxy.
                 */
                contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                    /**
                     * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                     *
                     * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                     * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                     */
                    constructor(address _logic, bytes memory _data) payable {
                        assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                        _upgradeToAndCall(_logic, _data, false);
                    }
                    /**
                     * @dev Returns the current implementation address.
                     */
                    function _implementation() internal view virtual override returns (address impl) {
                        return ERC1967Upgrade._getImplementation();
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (proxy/Proxy.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                 * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                 * be specified by overriding the virtual {_implementation} function.
                 *
                 * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                 * different contract through the {_delegate} function.
                 *
                 * The success and return data of the delegated call will be returned back to the caller of the proxy.
                 */
                abstract contract Proxy {
                    /**
                     * @dev Delegates the current call to `implementation`.
                     *
                     * This function does not return to its internal call site, it will return directly to the external caller.
                     */
                    function _delegate(address implementation) internal virtual {
                        assembly {
                            // Copy msg.data. We take full control of memory in this inline assembly
                            // block because it will not return to Solidity code. We overwrite the
                            // Solidity scratch pad at memory position 0.
                            calldatacopy(0, 0, calldatasize())
                            // Call the implementation.
                            // out and outsize are 0 because we don't know the size yet.
                            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                            // Copy the returned data.
                            returndatacopy(0, 0, returndatasize())
                            switch result
                            // delegatecall returns 0 on error.
                            case 0 {
                                revert(0, returndatasize())
                            }
                            default {
                                return(0, returndatasize())
                            }
                        }
                    }
                    /**
                     * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                     * and {_fallback} should delegate.
                     */
                    function _implementation() internal view virtual returns (address);
                    /**
                     * @dev Delegates the current call to the address returned by `_implementation()`.
                     *
                     * This function does not return to its internall call site, it will return directly to the external caller.
                     */
                    function _fallback() internal virtual {
                        _beforeFallback();
                        _delegate(_implementation());
                    }
                    /**
                     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                     * function in the contract matches the call data.
                     */
                    fallback() external payable virtual {
                        _fallback();
                    }
                    /**
                     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                     * is empty.
                     */
                    receive() external payable virtual {
                        _fallback();
                    }
                    /**
                     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                     * call, or as part of the Solidity `fallback` or `receive` functions.
                     *
                     * If overriden should call `super._beforeFallback()`.
                     */
                    function _beforeFallback() internal virtual {}
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
                pragma solidity ^0.8.2;
                import "../beacon/IBeacon.sol";
                import "../../interfaces/draft-IERC1822.sol";
                import "../../utils/Address.sol";
                import "../../utils/StorageSlot.sol";
                /**
                 * @dev This abstract contract provides getters and event emitting update functions for
                 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                 *
                 * _Available since v4.1._
                 *
                 * @custom:oz-upgrades-unsafe-allow delegatecall
                 */
                abstract contract ERC1967Upgrade {
                    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                    /**
                     * @dev Storage slot with the address of the current implementation.
                     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                     * validated in the constructor.
                     */
                    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                    /**
                     * @dev Emitted when the implementation is upgraded.
                     */
                    event Upgraded(address indexed implementation);
                    /**
                     * @dev Returns the current implementation address.
                     */
                    function _getImplementation() internal view returns (address) {
                        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                    }
                    /**
                     * @dev Stores a new address in the EIP1967 implementation slot.
                     */
                    function _setImplementation(address newImplementation) private {
                        require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                    }
                    /**
                     * @dev Perform implementation upgrade
                     *
                     * Emits an {Upgraded} event.
                     */
                    function _upgradeTo(address newImplementation) internal {
                        _setImplementation(newImplementation);
                        emit Upgraded(newImplementation);
                    }
                    /**
                     * @dev Perform implementation upgrade with additional setup call.
                     *
                     * Emits an {Upgraded} event.
                     */
                    function _upgradeToAndCall(
                        address newImplementation,
                        bytes memory data,
                        bool forceCall
                    ) internal {
                        _upgradeTo(newImplementation);
                        if (data.length > 0 || forceCall) {
                            Address.functionDelegateCall(newImplementation, data);
                        }
                    }
                    /**
                     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                     *
                     * Emits an {Upgraded} event.
                     */
                    function _upgradeToAndCallUUPS(
                        address newImplementation,
                        bytes memory data,
                        bool forceCall
                    ) internal {
                        // Upgrades from old implementations will perform a rollback test. This test requires the new
                        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                        // this special case will break upgrade paths from old UUPS implementation to new ones.
                        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
                            _setImplementation(newImplementation);
                        } else {
                            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                            } catch {
                                revert("ERC1967Upgrade: new implementation is not UUPS");
                            }
                            _upgradeToAndCall(newImplementation, data, forceCall);
                        }
                    }
                    /**
                     * @dev Storage slot with the admin of the contract.
                     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                     * validated in the constructor.
                     */
                    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                    /**
                     * @dev Emitted when the admin account has changed.
                     */
                    event AdminChanged(address previousAdmin, address newAdmin);
                    /**
                     * @dev Returns the current admin.
                     */
                    function _getAdmin() internal view returns (address) {
                        return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                    }
                    /**
                     * @dev Stores a new address in the EIP1967 admin slot.
                     */
                    function _setAdmin(address newAdmin) private {
                        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                    }
                    /**
                     * @dev Changes the admin of the proxy.
                     *
                     * Emits an {AdminChanged} event.
                     */
                    function _changeAdmin(address newAdmin) internal {
                        emit AdminChanged(_getAdmin(), newAdmin);
                        _setAdmin(newAdmin);
                    }
                    /**
                     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                     */
                    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                    /**
                     * @dev Emitted when the beacon is upgraded.
                     */
                    event BeaconUpgraded(address indexed beacon);
                    /**
                     * @dev Returns the current beacon.
                     */
                    function _getBeacon() internal view returns (address) {
                        return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                    }
                    /**
                     * @dev Stores a new beacon in the EIP1967 beacon slot.
                     */
                    function _setBeacon(address newBeacon) private {
                        require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                        require(
                            Address.isContract(IBeacon(newBeacon).implementation()),
                            "ERC1967: beacon implementation is not a contract"
                        );
                        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                    }
                    /**
                     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                     *
                     * Emits a {BeaconUpgraded} event.
                     */
                    function _upgradeBeaconToAndCall(
                        address newBeacon,
                        bytes memory data,
                        bool forceCall
                    ) internal {
                        _setBeacon(newBeacon);
                        emit BeaconUpgraded(newBeacon);
                        if (data.length > 0 || forceCall) {
                            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev This is the interface that {BeaconProxy} expects of its beacon.
                 */
                interface IBeacon {
                    /**
                     * @dev Must return an address that can be used as a delegate call target.
                     *
                     * {BeaconProxy} will check that this address is a contract.
                     */
                    function implementation() external view returns (address);
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
                 * proxy whose upgrades are fully controlled by the current implementation.
                 */
                interface IERC1822Proxiable {
                    /**
                     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
                     * address.
                     *
                     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                     * function revert if invoked through a proxy.
                     */
                    function proxiableUUID() external view returns (bytes32);
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
                pragma solidity ^0.8.1;
                /**
                 * @dev Collection of functions related to the address type
                 */
                library Address {
                    /**
                     * @dev Returns true if `account` is a contract.
                     *
                     * [IMPORTANT]
                     * ====
                     * It is unsafe to assume that an address for which this function returns
                     * false is an externally-owned account (EOA) and not a contract.
                     *
                     * Among others, `isContract` will return false for the following
                     * types of addresses:
                     *
                     *  - an externally-owned account
                     *  - a contract in construction
                     *  - an address where a contract will be created
                     *  - an address where a contract lived, but was destroyed
                     * ====
                     *
                     * [IMPORTANT]
                     * ====
                     * You shouldn't rely on `isContract` to protect against flash loan attacks!
                     *
                     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                     * constructor.
                     * ====
                     */
                    function isContract(address account) internal view returns (bool) {
                        // This method relies on extcodesize/address.code.length, which returns 0
                        // for contracts in construction, since the code is only stored at the end
                        // of the constructor execution.
                        return account.code.length > 0;
                    }
                    /**
                     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                     * `recipient`, forwarding all available gas and reverting on errors.
                     *
                     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                     * of certain opcodes, possibly making contracts go over the 2300 gas limit
                     * imposed by `transfer`, making them unable to receive funds via
                     * `transfer`. {sendValue} removes this limitation.
                     *
                     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                     *
                     * IMPORTANT: because control is transferred to `recipient`, care must be
                     * taken to not create reentrancy vulnerabilities. Consider using
                     * {ReentrancyGuard} or the
                     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                     */
                    function sendValue(address payable recipient, uint256 amount) internal {
                        require(address(this).balance >= amount, "Address: insufficient balance");
                        (bool success, ) = recipient.call{value: amount}("");
                        require(success, "Address: unable to send value, recipient may have reverted");
                    }
                    /**
                     * @dev Performs a Solidity function call using a low level `call`. A
                     * plain `call` is an unsafe replacement for a function call: use this
                     * function instead.
                     *
                     * If `target` reverts with a revert reason, it is bubbled up by this
                     * function (like regular Solidity function calls).
                     *
                     * Returns the raw returned data. To convert to the expected return value,
                     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                     *
                     * Requirements:
                     *
                     * - `target` must be a contract.
                     * - calling `target` with `data` must not revert.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionCall(target, data, "Address: low-level call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                     * `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, 0, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but also transferring `value` wei to `target`.
                     *
                     * Requirements:
                     *
                     * - the calling contract must have an ETH balance of at least `value`.
                     * - the called Solidity function must be `payable`.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                     * with `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(address(this).balance >= value, "Address: insufficient balance for call");
                        require(isContract(target), "Address: call to non-contract");
                        (bool success, bytes memory returndata) = target.call{value: value}(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                        return functionStaticCall(target, data, "Address: low-level static call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal view returns (bytes memory) {
                        require(isContract(target), "Address: static call to non-contract");
                        (bool success, bytes memory returndata) = target.staticcall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a delegate call.
                     *
                     * _Available since v3.4._
                     */
                    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a delegate call.
                     *
                     * _Available since v3.4._
                     */
                    function functionDelegateCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(isContract(target), "Address: delegate call to non-contract");
                        (bool success, bytes memory returndata) = target.delegatecall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                     * revert reason using the provided one.
                     *
                     * _Available since v4.3._
                     */
                    function verifyCallResult(
                        bool success,
                        bytes memory returndata,
                        string memory errorMessage
                    ) internal pure returns (bytes memory) {
                        if (success) {
                            return returndata;
                        } else {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert(errorMessage);
                            }
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev Library for reading and writing primitive types to specific storage slots.
                 *
                 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                 * This library helps with reading and writing to such slots without the need for inline assembly.
                 *
                 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                 *
                 * Example usage to set ERC1967 implementation slot:
                 * ```
                 * contract ERC1967 {
                 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                 *
                 *     function _getImplementation() internal view returns (address) {
                 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                 *     }
                 *
                 *     function _setImplementation(address newImplementation) internal {
                 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                 *     }
                 * }
                 * ```
                 *
                 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                 */
                library StorageSlot {
                    struct AddressSlot {
                        address value;
                    }
                    struct BooleanSlot {
                        bool value;
                    }
                    struct Bytes32Slot {
                        bytes32 value;
                    }
                    struct Uint256Slot {
                        uint256 value;
                    }
                    /**
                     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                     */
                    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                     */
                    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                     */
                    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                     */
                    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                }
                

                File 4 of 6: TransparentUpgradeableProxy
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)
                pragma solidity ^0.8.0;
                import "../ERC1967/ERC1967Proxy.sol";
                /**
                 * @dev This contract implements a proxy that is upgradeable by an admin.
                 *
                 * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
                 * clashing], which can potentially be used in an attack, this contract uses the
                 * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
                 * things that go hand in hand:
                 *
                 * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
                 * that call matches one of the admin functions exposed by the proxy itself.
                 * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
                 * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
                 * "admin cannot fallback to proxy target".
                 *
                 * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
                 * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
                 * to sudden errors when trying to call a function from the proxy implementation.
                 *
                 * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
                 * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
                 */
                contract TransparentUpgradeableProxy is ERC1967Proxy {
                    /**
                     * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                     * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                     */
                    constructor(
                        address _logic,
                        address admin_,
                        bytes memory _data
                    ) payable ERC1967Proxy(_logic, _data) {
                        assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                        _changeAdmin(admin_);
                    }
                    /**
                     * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                     */
                    modifier ifAdmin() {
                        if (msg.sender == _getAdmin()) {
                            _;
                        } else {
                            _fallback();
                        }
                    }
                    /**
                     * @dev Returns the current admin.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                     *
                     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                     * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                     * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                     */
                    function admin() external ifAdmin returns (address admin_) {
                        admin_ = _getAdmin();
                    }
                    /**
                     * @dev Returns the current implementation.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                     *
                     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                     * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                     * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                     */
                    function implementation() external ifAdmin returns (address implementation_) {
                        implementation_ = _implementation();
                    }
                    /**
                     * @dev Changes the admin of the proxy.
                     *
                     * Emits an {AdminChanged} event.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                     */
                    function changeAdmin(address newAdmin) external virtual ifAdmin {
                        _changeAdmin(newAdmin);
                    }
                    /**
                     * @dev Upgrade the implementation of the proxy.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                     */
                    function upgradeTo(address newImplementation) external ifAdmin {
                        _upgradeToAndCall(newImplementation, bytes(""), false);
                    }
                    /**
                     * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                     * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                     * proxied contract.
                     *
                     * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                     */
                    function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                        _upgradeToAndCall(newImplementation, data, true);
                    }
                    /**
                     * @dev Returns the current admin.
                     */
                    function _admin() internal view virtual returns (address) {
                        return _getAdmin();
                    }
                    /**
                     * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                     */
                    function _beforeFallback() internal virtual override {
                        require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                        super._beforeFallback();
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)
                pragma solidity ^0.8.0;
                import "../Proxy.sol";
                import "./ERC1967Upgrade.sol";
                /**
                 * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
                 * implementation address that can be changed. This address is stored in storage in the location specified by
                 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
                 * implementation behind the proxy.
                 */
                contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                    /**
                     * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                     *
                     * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                     * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                     */
                    constructor(address _logic, bytes memory _data) payable {
                        assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                        _upgradeToAndCall(_logic, _data, false);
                    }
                    /**
                     * @dev Returns the current implementation address.
                     */
                    function _implementation() internal view virtual override returns (address impl) {
                        return ERC1967Upgrade._getImplementation();
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (proxy/Proxy.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
                 * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
                 * be specified by overriding the virtual {_implementation} function.
                 *
                 * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
                 * different contract through the {_delegate} function.
                 *
                 * The success and return data of the delegated call will be returned back to the caller of the proxy.
                 */
                abstract contract Proxy {
                    /**
                     * @dev Delegates the current call to `implementation`.
                     *
                     * This function does not return to its internal call site, it will return directly to the external caller.
                     */
                    function _delegate(address implementation) internal virtual {
                        assembly {
                            // Copy msg.data. We take full control of memory in this inline assembly
                            // block because it will not return to Solidity code. We overwrite the
                            // Solidity scratch pad at memory position 0.
                            calldatacopy(0, 0, calldatasize())
                            // Call the implementation.
                            // out and outsize are 0 because we don't know the size yet.
                            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                            // Copy the returned data.
                            returndatacopy(0, 0, returndatasize())
                            switch result
                            // delegatecall returns 0 on error.
                            case 0 {
                                revert(0, returndatasize())
                            }
                            default {
                                return(0, returndatasize())
                            }
                        }
                    }
                    /**
                     * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                     * and {_fallback} should delegate.
                     */
                    function _implementation() internal view virtual returns (address);
                    /**
                     * @dev Delegates the current call to the address returned by `_implementation()`.
                     *
                     * This function does not return to its internall call site, it will return directly to the external caller.
                     */
                    function _fallback() internal virtual {
                        _beforeFallback();
                        _delegate(_implementation());
                    }
                    /**
                     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                     * function in the contract matches the call data.
                     */
                    fallback() external payable virtual {
                        _fallback();
                    }
                    /**
                     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                     * is empty.
                     */
                    receive() external payable virtual {
                        _fallback();
                    }
                    /**
                     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                     * call, or as part of the Solidity `fallback` or `receive` functions.
                     *
                     * If overriden should call `super._beforeFallback()`.
                     */
                    function _beforeFallback() internal virtual {}
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
                pragma solidity ^0.8.2;
                import "../beacon/IBeacon.sol";
                import "../../interfaces/draft-IERC1822.sol";
                import "../../utils/Address.sol";
                import "../../utils/StorageSlot.sol";
                /**
                 * @dev This abstract contract provides getters and event emitting update functions for
                 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                 *
                 * _Available since v4.1._
                 *
                 * @custom:oz-upgrades-unsafe-allow delegatecall
                 */
                abstract contract ERC1967Upgrade {
                    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                    /**
                     * @dev Storage slot with the address of the current implementation.
                     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                     * validated in the constructor.
                     */
                    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                    /**
                     * @dev Emitted when the implementation is upgraded.
                     */
                    event Upgraded(address indexed implementation);
                    /**
                     * @dev Returns the current implementation address.
                     */
                    function _getImplementation() internal view returns (address) {
                        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                    }
                    /**
                     * @dev Stores a new address in the EIP1967 implementation slot.
                     */
                    function _setImplementation(address newImplementation) private {
                        require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                    }
                    /**
                     * @dev Perform implementation upgrade
                     *
                     * Emits an {Upgraded} event.
                     */
                    function _upgradeTo(address newImplementation) internal {
                        _setImplementation(newImplementation);
                        emit Upgraded(newImplementation);
                    }
                    /**
                     * @dev Perform implementation upgrade with additional setup call.
                     *
                     * Emits an {Upgraded} event.
                     */
                    function _upgradeToAndCall(
                        address newImplementation,
                        bytes memory data,
                        bool forceCall
                    ) internal {
                        _upgradeTo(newImplementation);
                        if (data.length > 0 || forceCall) {
                            Address.functionDelegateCall(newImplementation, data);
                        }
                    }
                    /**
                     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                     *
                     * Emits an {Upgraded} event.
                     */
                    function _upgradeToAndCallUUPS(
                        address newImplementation,
                        bytes memory data,
                        bool forceCall
                    ) internal {
                        // Upgrades from old implementations will perform a rollback test. This test requires the new
                        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                        // this special case will break upgrade paths from old UUPS implementation to new ones.
                        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
                            _setImplementation(newImplementation);
                        } else {
                            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                            } catch {
                                revert("ERC1967Upgrade: new implementation is not UUPS");
                            }
                            _upgradeToAndCall(newImplementation, data, forceCall);
                        }
                    }
                    /**
                     * @dev Storage slot with the admin of the contract.
                     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                     * validated in the constructor.
                     */
                    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                    /**
                     * @dev Emitted when the admin account has changed.
                     */
                    event AdminChanged(address previousAdmin, address newAdmin);
                    /**
                     * @dev Returns the current admin.
                     */
                    function _getAdmin() internal view returns (address) {
                        return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                    }
                    /**
                     * @dev Stores a new address in the EIP1967 admin slot.
                     */
                    function _setAdmin(address newAdmin) private {
                        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                    }
                    /**
                     * @dev Changes the admin of the proxy.
                     *
                     * Emits an {AdminChanged} event.
                     */
                    function _changeAdmin(address newAdmin) internal {
                        emit AdminChanged(_getAdmin(), newAdmin);
                        _setAdmin(newAdmin);
                    }
                    /**
                     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                     */
                    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                    /**
                     * @dev Emitted when the beacon is upgraded.
                     */
                    event BeaconUpgraded(address indexed beacon);
                    /**
                     * @dev Returns the current beacon.
                     */
                    function _getBeacon() internal view returns (address) {
                        return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                    }
                    /**
                     * @dev Stores a new beacon in the EIP1967 beacon slot.
                     */
                    function _setBeacon(address newBeacon) private {
                        require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                        require(
                            Address.isContract(IBeacon(newBeacon).implementation()),
                            "ERC1967: beacon implementation is not a contract"
                        );
                        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                    }
                    /**
                     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                     *
                     * Emits a {BeaconUpgraded} event.
                     */
                    function _upgradeBeaconToAndCall(
                        address newBeacon,
                        bytes memory data,
                        bool forceCall
                    ) internal {
                        _setBeacon(newBeacon);
                        emit BeaconUpgraded(newBeacon);
                        if (data.length > 0 || forceCall) {
                            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev This is the interface that {BeaconProxy} expects of its beacon.
                 */
                interface IBeacon {
                    /**
                     * @dev Must return an address that can be used as a delegate call target.
                     *
                     * {BeaconProxy} will check that this address is a contract.
                     */
                    function implementation() external view returns (address);
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
                 * proxy whose upgrades are fully controlled by the current implementation.
                 */
                interface IERC1822Proxiable {
                    /**
                     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
                     * address.
                     *
                     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                     * function revert if invoked through a proxy.
                     */
                    function proxiableUUID() external view returns (bytes32);
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
                pragma solidity ^0.8.1;
                /**
                 * @dev Collection of functions related to the address type
                 */
                library Address {
                    /**
                     * @dev Returns true if `account` is a contract.
                     *
                     * [IMPORTANT]
                     * ====
                     * It is unsafe to assume that an address for which this function returns
                     * false is an externally-owned account (EOA) and not a contract.
                     *
                     * Among others, `isContract` will return false for the following
                     * types of addresses:
                     *
                     *  - an externally-owned account
                     *  - a contract in construction
                     *  - an address where a contract will be created
                     *  - an address where a contract lived, but was destroyed
                     * ====
                     *
                     * [IMPORTANT]
                     * ====
                     * You shouldn't rely on `isContract` to protect against flash loan attacks!
                     *
                     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                     * constructor.
                     * ====
                     */
                    function isContract(address account) internal view returns (bool) {
                        // This method relies on extcodesize/address.code.length, which returns 0
                        // for contracts in construction, since the code is only stored at the end
                        // of the constructor execution.
                        return account.code.length > 0;
                    }
                    /**
                     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                     * `recipient`, forwarding all available gas and reverting on errors.
                     *
                     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                     * of certain opcodes, possibly making contracts go over the 2300 gas limit
                     * imposed by `transfer`, making them unable to receive funds via
                     * `transfer`. {sendValue} removes this limitation.
                     *
                     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                     *
                     * IMPORTANT: because control is transferred to `recipient`, care must be
                     * taken to not create reentrancy vulnerabilities. Consider using
                     * {ReentrancyGuard} or the
                     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                     */
                    function sendValue(address payable recipient, uint256 amount) internal {
                        require(address(this).balance >= amount, "Address: insufficient balance");
                        (bool success, ) = recipient.call{value: amount}("");
                        require(success, "Address: unable to send value, recipient may have reverted");
                    }
                    /**
                     * @dev Performs a Solidity function call using a low level `call`. A
                     * plain `call` is an unsafe replacement for a function call: use this
                     * function instead.
                     *
                     * If `target` reverts with a revert reason, it is bubbled up by this
                     * function (like regular Solidity function calls).
                     *
                     * Returns the raw returned data. To convert to the expected return value,
                     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                     *
                     * Requirements:
                     *
                     * - `target` must be a contract.
                     * - calling `target` with `data` must not revert.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionCall(target, data, "Address: low-level call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                     * `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, 0, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but also transferring `value` wei to `target`.
                     *
                     * Requirements:
                     *
                     * - the calling contract must have an ETH balance of at least `value`.
                     * - the called Solidity function must be `payable`.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                     * with `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(address(this).balance >= value, "Address: insufficient balance for call");
                        require(isContract(target), "Address: call to non-contract");
                        (bool success, bytes memory returndata) = target.call{value: value}(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                        return functionStaticCall(target, data, "Address: low-level static call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal view returns (bytes memory) {
                        require(isContract(target), "Address: static call to non-contract");
                        (bool success, bytes memory returndata) = target.staticcall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a delegate call.
                     *
                     * _Available since v3.4._
                     */
                    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a delegate call.
                     *
                     * _Available since v3.4._
                     */
                    function functionDelegateCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(isContract(target), "Address: delegate call to non-contract");
                        (bool success, bytes memory returndata) = target.delegatecall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                     * revert reason using the provided one.
                     *
                     * _Available since v4.3._
                     */
                    function verifyCallResult(
                        bool success,
                        bytes memory returndata,
                        string memory errorMessage
                    ) internal pure returns (bytes memory) {
                        if (success) {
                            return returndata;
                        } else {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert(errorMessage);
                            }
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev Library for reading and writing primitive types to specific storage slots.
                 *
                 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                 * This library helps with reading and writing to such slots without the need for inline assembly.
                 *
                 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                 *
                 * Example usage to set ERC1967 implementation slot:
                 * ```
                 * contract ERC1967 {
                 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                 *
                 *     function _getImplementation() internal view returns (address) {
                 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                 *     }
                 *
                 *     function _setImplementation(address newImplementation) internal {
                 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                 *     }
                 * }
                 * ```
                 *
                 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                 */
                library StorageSlot {
                    struct AddressSlot {
                        address value;
                    }
                    struct BooleanSlot {
                        bool value;
                    }
                    struct Bytes32Slot {
                        bytes32 value;
                    }
                    struct Uint256Slot {
                        uint256 value;
                    }
                    /**
                     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                     */
                    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                     */
                    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                     */
                    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                     */
                    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                }
                

                File 5 of 6: ERC20Inbox
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)
                pragma solidity ^0.8.0;
                import "../../utils/AddressUpgradeable.sol";
                /**
                 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
                 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                 *
                 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                 *
                 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                 *
                 * [CAUTION]
                 * ====
                 * Avoid leaving a contract uninitialized.
                 *
                 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
                 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
                 *
                 * [.hljs-theme-light.nopadding]
                 * ```
                 * /// @custom:oz-upgrades-unsafe-allow constructor
                 * constructor() initializer {}
                 * ```
                 * ====
                 */
                abstract contract Initializable {
                    /**
                     * @dev Indicates that the contract has been initialized.
                     */
                    bool private _initialized;
                    /**
                     * @dev Indicates that the contract is in the process of being initialized.
                     */
                    bool private _initializing;
                    /**
                     * @dev Modifier to protect an initializer function from being invoked twice.
                     */
                    modifier initializer() {
                        // If the contract is initializing we ignore whether _initialized is set in order to support multiple
                        // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
                        // contract may have been reentered.
                        require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");
                        bool isTopLevelCall = !_initializing;
                        if (isTopLevelCall) {
                            _initializing = true;
                            _initialized = true;
                        }
                        _;
                        if (isTopLevelCall) {
                            _initializing = false;
                        }
                    }
                    /**
                     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                     * {initializer} modifier, directly or indirectly.
                     */
                    modifier onlyInitializing() {
                        require(_initializing, "Initializable: contract is not initializing");
                        _;
                    }
                    function _isConstructor() private view returns (bool) {
                        return !AddressUpgradeable.isContract(address(this));
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)
                pragma solidity ^0.8.0;
                import "../utils/ContextUpgradeable.sol";
                import "../proxy/utils/Initializable.sol";
                /**
                 * @dev Contract module which allows children to implement an emergency stop
                 * mechanism that can be triggered by an authorized account.
                 *
                 * This module is used through inheritance. It will make available the
                 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
                 * the functions of your contract. Note that they will not be pausable by
                 * simply including this module, only once the modifiers are put in place.
                 */
                abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
                    /**
                     * @dev Emitted when the pause is triggered by `account`.
                     */
                    event Paused(address account);
                    /**
                     * @dev Emitted when the pause is lifted by `account`.
                     */
                    event Unpaused(address account);
                    bool private _paused;
                    /**
                     * @dev Initializes the contract in unpaused state.
                     */
                    function __Pausable_init() internal onlyInitializing {
                        __Pausable_init_unchained();
                    }
                    function __Pausable_init_unchained() internal onlyInitializing {
                        _paused = false;
                    }
                    /**
                     * @dev Returns true if the contract is paused, and false otherwise.
                     */
                    function paused() public view virtual returns (bool) {
                        return _paused;
                    }
                    /**
                     * @dev Modifier to make a function callable only when the contract is not paused.
                     *
                     * Requirements:
                     *
                     * - The contract must not be paused.
                     */
                    modifier whenNotPaused() {
                        require(!paused(), "Pausable: paused");
                        _;
                    }
                    /**
                     * @dev Modifier to make a function callable only when the contract is paused.
                     *
                     * Requirements:
                     *
                     * - The contract must be paused.
                     */
                    modifier whenPaused() {
                        require(paused(), "Pausable: not paused");
                        _;
                    }
                    /**
                     * @dev Triggers stopped state.
                     *
                     * Requirements:
                     *
                     * - The contract must not be paused.
                     */
                    function _pause() internal virtual whenNotPaused {
                        _paused = true;
                        emit Paused(_msgSender());
                    }
                    /**
                     * @dev Returns to normal state.
                     *
                     * Requirements:
                     *
                     * - The contract must be paused.
                     */
                    function _unpause() internal virtual whenPaused {
                        _paused = false;
                        emit Unpaused(_msgSender());
                    }
                    /**
                     * @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) (utils/Address.sol)
                pragma solidity ^0.8.1;
                /**
                 * @dev Collection of functions related to the address type
                 */
                library AddressUpgradeable {
                    /**
                     * @dev Returns true if `account` is a contract.
                     *
                     * [IMPORTANT]
                     * ====
                     * It is unsafe to assume that an address for which this function returns
                     * false is an externally-owned account (EOA) and not a contract.
                     *
                     * Among others, `isContract` will return false for the following
                     * types of addresses:
                     *
                     *  - an externally-owned account
                     *  - a contract in construction
                     *  - an address where a contract will be created
                     *  - an address where a contract lived, but was destroyed
                     * ====
                     *
                     * [IMPORTANT]
                     * ====
                     * You shouldn't rely on `isContract` to protect against flash loan attacks!
                     *
                     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                     * constructor.
                     * ====
                     */
                    function isContract(address account) internal view returns (bool) {
                        // This method relies on extcodesize/address.code.length, which returns 0
                        // for contracts in construction, since the code is only stored at the end
                        // of the constructor execution.
                        return account.code.length > 0;
                    }
                    /**
                     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                     * `recipient`, forwarding all available gas and reverting on errors.
                     *
                     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                     * of certain opcodes, possibly making contracts go over the 2300 gas limit
                     * imposed by `transfer`, making them unable to receive funds via
                     * `transfer`. {sendValue} removes this limitation.
                     *
                     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                     *
                     * IMPORTANT: because control is transferred to `recipient`, care must be
                     * taken to not create reentrancy vulnerabilities. Consider using
                     * {ReentrancyGuard} or the
                     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                     */
                    function sendValue(address payable recipient, uint256 amount) internal {
                        require(address(this).balance >= amount, "Address: insufficient balance");
                        (bool success, ) = recipient.call{value: amount}("");
                        require(success, "Address: unable to send value, recipient may have reverted");
                    }
                    /**
                     * @dev Performs a Solidity function call using a low level `call`. A
                     * plain `call` is an unsafe replacement for a function call: use this
                     * function instead.
                     *
                     * If `target` reverts with a revert reason, it is bubbled up by this
                     * function (like regular Solidity function calls).
                     *
                     * Returns the raw returned data. To convert to the expected return value,
                     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                     *
                     * Requirements:
                     *
                     * - `target` must be a contract.
                     * - calling `target` with `data` must not revert.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionCall(target, data, "Address: low-level call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                     * `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, 0, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but also transferring `value` wei to `target`.
                     *
                     * Requirements:
                     *
                     * - the calling contract must have an ETH balance of at least `value`.
                     * - the called Solidity function must be `payable`.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                     * with `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(address(this).balance >= value, "Address: insufficient balance for call");
                        require(isContract(target), "Address: call to non-contract");
                        (bool success, bytes memory returndata) = target.call{value: value}(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                        return functionStaticCall(target, data, "Address: low-level static call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal view returns (bytes memory) {
                        require(isContract(target), "Address: static call to non-contract");
                        (bool success, bytes memory returndata) = target.staticcall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                     * revert reason using the provided one.
                     *
                     * _Available since v4.3._
                     */
                    function verifyCallResult(
                        bool success,
                        bytes memory returndata,
                        string memory errorMessage
                    ) internal pure returns (bytes memory) {
                        if (success) {
                            return returndata;
                        } else {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert(errorMessage);
                            }
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
                pragma solidity ^0.8.0;
                import "../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;
                    }
                    /**
                     * @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 v4.4.1 (utils/StorageSlot.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev Library for reading and writing primitive types to specific storage slots.
                 *
                 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                 * This library helps with reading and writing to such slots without the need for inline assembly.
                 *
                 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                 *
                 * Example usage to set ERC1967 implementation slot:
                 * ```
                 * contract ERC1967 {
                 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                 *
                 *     function _getImplementation() internal view returns (address) {
                 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                 *     }
                 *
                 *     function _setImplementation(address newImplementation) internal {
                 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                 *     }
                 * }
                 * ```
                 *
                 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                 */
                library StorageSlotUpgradeable {
                    struct AddressSlot {
                        address value;
                    }
                    struct BooleanSlot {
                        bool value;
                    }
                    struct Bytes32Slot {
                        bytes32 value;
                    }
                    struct Uint256Slot {
                        uint256 value;
                    }
                    /**
                     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                     */
                    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                     */
                    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                     */
                    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                    /**
                     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                     */
                    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                        assembly {
                            r.slot := slot
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)
                pragma solidity ^0.8.0;
                import "./IERC20.sol";
                import "./extensions/IERC20Metadata.sol";
                import "../../utils/Context.sol";
                /**
                 * @dev Implementation of the {IERC20} interface.
                 *
                 * This implementation is agnostic to the way tokens are created. This means
                 * that a supply mechanism has to be added in a derived contract using {_mint}.
                 * For a generic mechanism see {ERC20PresetMinterPauser}.
                 *
                 * TIP: For a detailed writeup see our guide
                 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
                 * to implement supply mechanisms].
                 *
                 * We have followed general OpenZeppelin Contracts guidelines: functions revert
                 * instead returning `false` on failure. This behavior is nonetheless
                 * conventional and does not conflict with the expectations of ERC20
                 * applications.
                 *
                 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
                 * This allows applications to reconstruct the allowance for all accounts just
                 * by listening to said events. Other implementations of the EIP may not emit
                 * these events, as it isn't required by the specification.
                 *
                 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
                 * functions have been added to mitigate the well-known issues around setting
                 * allowances. See {IERC20-approve}.
                 */
                contract ERC20 is Context, IERC20, IERC20Metadata {
                    mapping(address => uint256) private _balances;
                    mapping(address => mapping(address => uint256)) private _allowances;
                    uint256 private _totalSupply;
                    string private _name;
                    string private _symbol;
                    /**
                     * @dev Sets the values for {name} and {symbol}.
                     *
                     * The default value of {decimals} is 18. To select a different value for
                     * {decimals} you should overload it.
                     *
                     * All two of these values are immutable: they can only be set once during
                     * construction.
                     */
                    constructor(string memory name_, string memory symbol_) {
                        _name = name_;
                        _symbol = symbol_;
                    }
                    /**
                     * @dev Returns the name of the token.
                     */
                    function name() public view virtual override returns (string memory) {
                        return _name;
                    }
                    /**
                     * @dev Returns the symbol of the token, usually a shorter version of the
                     * name.
                     */
                    function symbol() public view virtual override returns (string memory) {
                        return _symbol;
                    }
                    /**
                     * @dev Returns the number of decimals used to get its user representation.
                     * For example, if `decimals` equals `2`, a balance of `505` tokens should
                     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
                     *
                     * Tokens usually opt for a value of 18, imitating the relationship between
                     * Ether and Wei. This is the value {ERC20} uses, unless this function is
                     * overridden;
                     *
                     * NOTE: This information is only used for _display_ purposes: it in
                     * no way affects any of the arithmetic of the contract, including
                     * {IERC20-balanceOf} and {IERC20-transfer}.
                     */
                    function decimals() public view virtual override returns (uint8) {
                        return 18;
                    }
                    /**
                     * @dev See {IERC20-totalSupply}.
                     */
                    function totalSupply() public view virtual override returns (uint256) {
                        return _totalSupply;
                    }
                    /**
                     * @dev See {IERC20-balanceOf}.
                     */
                    function balanceOf(address account) public view virtual override returns (uint256) {
                        return _balances[account];
                    }
                    /**
                     * @dev See {IERC20-transfer}.
                     *
                     * Requirements:
                     *
                     * - `to` cannot be the zero address.
                     * - the caller must have a balance of at least `amount`.
                     */
                    function transfer(address to, uint256 amount) public virtual override returns (bool) {
                        address owner = _msgSender();
                        _transfer(owner, to, amount);
                        return true;
                    }
                    /**
                     * @dev See {IERC20-allowance}.
                     */
                    function allowance(address owner, address spender) public view virtual override returns (uint256) {
                        return _allowances[owner][spender];
                    }
                    /**
                     * @dev See {IERC20-approve}.
                     *
                     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
                     * `transferFrom`. This is semantically equivalent to an infinite approval.
                     *
                     * Requirements:
                     *
                     * - `spender` cannot be the zero address.
                     */
                    function approve(address spender, uint256 amount) public virtual override returns (bool) {
                        address owner = _msgSender();
                        _approve(owner, spender, amount);
                        return true;
                    }
                    /**
                     * @dev See {IERC20-transferFrom}.
                     *
                     * Emits an {Approval} event indicating the updated allowance. This is not
                     * required by the EIP. See the note at the beginning of {ERC20}.
                     *
                     * NOTE: Does not update the allowance if the current allowance
                     * is the maximum `uint256`.
                     *
                     * Requirements:
                     *
                     * - `from` and `to` cannot be the zero address.
                     * - `from` must have a balance of at least `amount`.
                     * - the caller must have allowance for ``from``'s tokens of at least
                     * `amount`.
                     */
                    function transferFrom(
                        address from,
                        address to,
                        uint256 amount
                    ) public virtual override returns (bool) {
                        address spender = _msgSender();
                        _spendAllowance(from, spender, amount);
                        _transfer(from, to, amount);
                        return true;
                    }
                    /**
                     * @dev Atomically increases the allowance granted to `spender` by the caller.
                     *
                     * This is an alternative to {approve} that can be used as a mitigation for
                     * problems described in {IERC20-approve}.
                     *
                     * Emits an {Approval} event indicating the updated allowance.
                     *
                     * Requirements:
                     *
                     * - `spender` cannot be the zero address.
                     */
                    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                        address owner = _msgSender();
                        _approve(owner, spender, _allowances[owner][spender] + addedValue);
                        return true;
                    }
                    /**
                     * @dev Atomically decreases the allowance granted to `spender` by the caller.
                     *
                     * This is an alternative to {approve} that can be used as a mitigation for
                     * problems described in {IERC20-approve}.
                     *
                     * Emits an {Approval} event indicating the updated allowance.
                     *
                     * Requirements:
                     *
                     * - `spender` cannot be the zero address.
                     * - `spender` must have allowance for the caller of at least
                     * `subtractedValue`.
                     */
                    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                        address owner = _msgSender();
                        uint256 currentAllowance = _allowances[owner][spender];
                        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
                        unchecked {
                            _approve(owner, spender, currentAllowance - subtractedValue);
                        }
                        return true;
                    }
                    /**
                     * @dev Moves `amount` of tokens from `sender` to `recipient`.
                     *
                     * This internal function is equivalent to {transfer}, and can be used to
                     * e.g. implement automatic token fees, slashing mechanisms, etc.
                     *
                     * Emits a {Transfer} event.
                     *
                     * Requirements:
                     *
                     * - `from` cannot be the zero address.
                     * - `to` cannot be the zero address.
                     * - `from` must have a balance of at least `amount`.
                     */
                    function _transfer(
                        address from,
                        address to,
                        uint256 amount
                    ) internal virtual {
                        require(from != address(0), "ERC20: transfer from the zero address");
                        require(to != address(0), "ERC20: transfer to the zero address");
                        _beforeTokenTransfer(from, to, amount);
                        uint256 fromBalance = _balances[from];
                        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
                        unchecked {
                            _balances[from] = fromBalance - amount;
                        }
                        _balances[to] += amount;
                        emit Transfer(from, to, amount);
                        _afterTokenTransfer(from, to, amount);
                    }
                    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                     * the total supply.
                     *
                     * Emits a {Transfer} event with `from` set to the zero address.
                     *
                     * Requirements:
                     *
                     * - `account` cannot be the zero address.
                     */
                    function _mint(address account, uint256 amount) internal virtual {
                        require(account != address(0), "ERC20: mint to the zero address");
                        _beforeTokenTransfer(address(0), account, amount);
                        _totalSupply += amount;
                        _balances[account] += amount;
                        emit Transfer(address(0), account, amount);
                        _afterTokenTransfer(address(0), account, amount);
                    }
                    /**
                     * @dev Destroys `amount` tokens from `account`, reducing the
                     * total supply.
                     *
                     * Emits a {Transfer} event with `to` set to the zero address.
                     *
                     * Requirements:
                     *
                     * - `account` cannot be the zero address.
                     * - `account` must have at least `amount` tokens.
                     */
                    function _burn(address account, uint256 amount) internal virtual {
                        require(account != address(0), "ERC20: burn from the zero address");
                        _beforeTokenTransfer(account, address(0), amount);
                        uint256 accountBalance = _balances[account];
                        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
                        unchecked {
                            _balances[account] = accountBalance - amount;
                        }
                        _totalSupply -= amount;
                        emit Transfer(account, address(0), amount);
                        _afterTokenTransfer(account, address(0), amount);
                    }
                    /**
                     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                     *
                     * This internal function is equivalent to `approve`, and can be used to
                     * e.g. set automatic allowances for certain subsystems, etc.
                     *
                     * Emits an {Approval} event.
                     *
                     * Requirements:
                     *
                     * - `owner` cannot be the zero address.
                     * - `spender` cannot be the zero address.
                     */
                    function _approve(
                        address owner,
                        address spender,
                        uint256 amount
                    ) internal virtual {
                        require(owner != address(0), "ERC20: approve from the zero address");
                        require(spender != address(0), "ERC20: approve to the zero address");
                        _allowances[owner][spender] = amount;
                        emit Approval(owner, spender, amount);
                    }
                    /**
                     * @dev Spend `amount` form the allowance of `owner` toward `spender`.
                     *
                     * Does not update the allowance amount in case of infinite allowance.
                     * Revert if not enough allowance is available.
                     *
                     * Might emit an {Approval} event.
                     */
                    function _spendAllowance(
                        address owner,
                        address spender,
                        uint256 amount
                    ) internal virtual {
                        uint256 currentAllowance = allowance(owner, spender);
                        if (currentAllowance != type(uint256).max) {
                            require(currentAllowance >= amount, "ERC20: insufficient allowance");
                            unchecked {
                                _approve(owner, spender, currentAllowance - amount);
                            }
                        }
                    }
                    /**
                     * @dev Hook that is called before any transfer of tokens. This includes
                     * minting and burning.
                     *
                     * Calling conditions:
                     *
                     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                     * will be transferred to `to`.
                     * - when `from` is zero, `amount` tokens will be minted for `to`.
                     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                     * - `from` and `to` are never both zero.
                     *
                     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                     */
                    function _beforeTokenTransfer(
                        address from,
                        address to,
                        uint256 amount
                    ) internal virtual {}
                    /**
                     * @dev Hook that is called after any transfer of tokens. This includes
                     * minting and burning.
                     *
                     * Calling conditions:
                     *
                     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                     * has been transferred to `to`.
                     * - when `from` is zero, `amount` tokens have been minted for `to`.
                     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
                     * - `from` and `to` are never both zero.
                     *
                     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                     */
                    function _afterTokenTransfer(
                        address from,
                        address to,
                        uint256 amount
                    ) internal virtual {}
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
                pragma solidity ^0.8.0;
                import "../IERC20.sol";
                /**
                 * @dev Interface for the optional metadata functions from the ERC20 standard.
                 *
                 * _Available since v4.1._
                 */
                interface IERC20Metadata is IERC20 {
                    /**
                     * @dev Returns the name of the token.
                     */
                    function name() external view returns (string memory);
                    /**
                     * @dev Returns the symbol of the token.
                     */
                    function symbol() external view returns (string memory);
                    /**
                     * @dev Returns the decimals places of the token.
                     */
                    function decimals() external view returns (uint8);
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev Interface of the ERC20 standard as defined in the EIP.
                 */
                interface IERC20 {
                    /**
                     * @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);
                    /**
                     * @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);
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
                pragma solidity ^0.8.0;
                import "../IERC20.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;
                    function safeTransfer(
                        IERC20 token,
                        address to,
                        uint256 value
                    ) internal {
                        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                    }
                    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));
                    }
                    function safeIncreaseAllowance(
                        IERC20 token,
                        address spender,
                        uint256 value
                    ) internal {
                        uint256 newAllowance = token.allowance(address(this), spender) + value;
                        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                    }
                    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");
                            uint256 newAllowance = oldAllowance - value;
                            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                        }
                    }
                    /**
                     * @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");
                        if (returndata.length > 0) {
                            // Return data is optional
                            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
                pragma solidity ^0.8.1;
                /**
                 * @dev Collection of functions related to the address type
                 */
                library Address {
                    /**
                     * @dev Returns true if `account` is a contract.
                     *
                     * [IMPORTANT]
                     * ====
                     * It is unsafe to assume that an address for which this function returns
                     * false is an externally-owned account (EOA) and not a contract.
                     *
                     * Among others, `isContract` will return false for the following
                     * types of addresses:
                     *
                     *  - an externally-owned account
                     *  - a contract in construction
                     *  - an address where a contract will be created
                     *  - an address where a contract lived, but was destroyed
                     * ====
                     *
                     * [IMPORTANT]
                     * ====
                     * You shouldn't rely on `isContract` to protect against flash loan attacks!
                     *
                     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                     * constructor.
                     * ====
                     */
                    function isContract(address account) internal view returns (bool) {
                        // This method relies on extcodesize/address.code.length, which returns 0
                        // for contracts in construction, since the code is only stored at the end
                        // of the constructor execution.
                        return account.code.length > 0;
                    }
                    /**
                     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                     * `recipient`, forwarding all available gas and reverting on errors.
                     *
                     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                     * of certain opcodes, possibly making contracts go over the 2300 gas limit
                     * imposed by `transfer`, making them unable to receive funds via
                     * `transfer`. {sendValue} removes this limitation.
                     *
                     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                     *
                     * IMPORTANT: because control is transferred to `recipient`, care must be
                     * taken to not create reentrancy vulnerabilities. Consider using
                     * {ReentrancyGuard} or the
                     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                     */
                    function sendValue(address payable recipient, uint256 amount) internal {
                        require(address(this).balance >= amount, "Address: insufficient balance");
                        (bool success, ) = recipient.call{value: amount}("");
                        require(success, "Address: unable to send value, recipient may have reverted");
                    }
                    /**
                     * @dev Performs a Solidity function call using a low level `call`. A
                     * plain `call` is an unsafe replacement for a function call: use this
                     * function instead.
                     *
                     * If `target` reverts with a revert reason, it is bubbled up by this
                     * function (like regular Solidity function calls).
                     *
                     * Returns the raw returned data. To convert to the expected return value,
                     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                     *
                     * Requirements:
                     *
                     * - `target` must be a contract.
                     * - calling `target` with `data` must not revert.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionCall(target, data, "Address: low-level call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                     * `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, 0, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but also transferring `value` wei to `target`.
                     *
                     * Requirements:
                     *
                     * - the calling contract must have an ETH balance of at least `value`.
                     * - the called Solidity function must be `payable`.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                     * with `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(address(this).balance >= value, "Address: insufficient balance for call");
                        require(isContract(target), "Address: call to non-contract");
                        (bool success, bytes memory returndata) = target.call{value: value}(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                        return functionStaticCall(target, data, "Address: low-level static call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal view returns (bytes memory) {
                        require(isContract(target), "Address: static call to non-contract");
                        (bool success, bytes memory returndata) = target.staticcall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a delegate call.
                     *
                     * _Available since v3.4._
                     */
                    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a delegate call.
                     *
                     * _Available since v3.4._
                     */
                    function functionDelegateCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(isContract(target), "Address: delegate call to non-contract");
                        (bool success, bytes memory returndata) = target.delegatecall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                     * revert reason using the provided one.
                     *
                     * _Available since v4.3._
                     */
                    function verifyCallResult(
                        bool success,
                        bytes memory returndata,
                        string memory errorMessage
                    ) internal pure returns (bytes memory) {
                        if (success) {
                            return returndata;
                        } else {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert(errorMessage);
                            }
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev Provides information about the current execution context, including the
                 * sender of the transaction and its data. While these are generally available
                 * via msg.sender and msg.data, they should not be accessed in such a direct
                 * manner, since when dealing with meta-transactions the account sending and
                 * paying for execution may not be the actual sender (as far as an application
                 * is concerned).
                 *
                 * This contract is only required for intermediate, library-like contracts.
                 */
                abstract contract Context {
                    function _msgSender() internal view virtual returns (address) {
                        return msg.sender;
                    }
                    function _msgData() internal view virtual returns (bytes calldata) {
                        return msg.data;
                    }
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/nitro/blob/master/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.4;
                import {
                    DataTooLarge,
                    GasLimitTooLarge,
                    InsufficientValue,
                    InsufficientSubmissionCost,
                    L1Forked,
                    NotAllowedOrigin,
                    NotOrigin,
                    NotRollupOrOwner,
                    RetryableData
                } from "../libraries/Error.sol";
                import "./IInboxBase.sol";
                import "./ISequencerInbox.sol";
                import "./IBridge.sol";
                import "../libraries/AddressAliasHelper.sol";
                import "../libraries/DelegateCallAware.sol";
                import {
                    L1MessageType_submitRetryableTx,
                    L2MessageType_unsignedContractTx,
                    L2MessageType_unsignedEOATx,
                    L2_MSG
                } from "../libraries/MessageTypes.sol";
                import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
                import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
                import "@openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol";
                /**
                 * @title Inbox for user and contract originated messages
                 * @notice Messages created via this inbox are enqueued in the delayed accumulator
                 * to await inclusion in the SequencerInbox
                 */
                abstract contract AbsInbox is DelegateCallAware, PausableUpgradeable, IInboxBase {
                    /// @dev Storage slot with the admin of the contract.
                    /// This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
                    bytes32 internal constant _ADMIN_SLOT =
                        0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                    /// @inheritdoc IInboxBase
                    IBridge public bridge;
                    /// @inheritdoc IInboxBase
                    ISequencerInbox public sequencerInbox;
                    /// ------------------------------------ allow list start ------------------------------------ ///
                    /// @inheritdoc IInboxBase
                    bool public allowListEnabled;
                    /// @inheritdoc IInboxBase
                    mapping(address => bool) public isAllowed;
                    event AllowListAddressSet(address indexed user, bool val);
                    event AllowListEnabledUpdated(bool isEnabled);
                    /// @inheritdoc IInboxBase
                    function setAllowList(address[] memory user, bool[] memory val) external onlyRollupOrOwner {
                        require(user.length == val.length, "INVALID_INPUT");
                        for (uint256 i = 0; i < user.length; i++) {
                            isAllowed[user[i]] = val[i];
                            emit AllowListAddressSet(user[i], val[i]);
                        }
                    }
                    /// @inheritdoc IInboxBase
                    function setAllowListEnabled(bool _allowListEnabled) external onlyRollupOrOwner {
                        require(_allowListEnabled != allowListEnabled, "ALREADY_SET");
                        allowListEnabled = _allowListEnabled;
                        emit AllowListEnabledUpdated(_allowListEnabled);
                    }
                    /// @dev this modifier checks the tx.origin instead of msg.sender for convenience (ie it allows
                    /// allowed users to interact with the token bridge without needing the token bridge to be allowList aware).
                    /// this modifier is not intended to use to be used for security (since this opens the allowList to
                    /// a smart contract phishing risk).
                    modifier onlyAllowed() {
                        // solhint-disable-next-line avoid-tx-origin
                        if (allowListEnabled && !isAllowed[tx.origin]) revert NotAllowedOrigin(tx.origin);
                        _;
                    }
                    /// ------------------------------------ allow list end ------------------------------------ ///
                    modifier onlyRollupOrOwner() {
                        IOwnable rollup = bridge.rollup();
                        if (msg.sender != address(rollup)) {
                            address rollupOwner = rollup.owner();
                            if (msg.sender != rollupOwner) {
                                revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
                            }
                        }
                        _;
                    }
                    // On L1 this should be set to 117964: 90% of Geth's 128KB tx size limit, leaving ~13KB for proving
                    uint256 public immutable maxDataSize;
                    uint256 internal immutable deployTimeChainId = block.chainid;
                    constructor(uint256 _maxDataSize) {
                        maxDataSize = _maxDataSize;
                    }
                    function _chainIdChanged() internal view returns (bool) {
                        return deployTimeChainId != block.chainid;
                    }
                    /// @inheritdoc IInboxBase
                    function pause() external onlyRollupOrOwner {
                        _pause();
                    }
                    /// @inheritdoc IInboxBase
                    function unpause() external onlyRollupOrOwner {
                        _unpause();
                    }
                    /* solhint-disable func-name-mixedcase */
                    function __AbsInbox_init(IBridge _bridge, ISequencerInbox _sequencerInbox)
                        internal
                        onlyInitializing
                    {
                        bridge = _bridge;
                        sequencerInbox = _sequencerInbox;
                        allowListEnabled = false;
                        __Pausable_init();
                    }
                    /// @inheritdoc IInboxBase
                    function sendL2MessageFromOrigin(bytes calldata messageData)
                        external
                        whenNotPaused
                        onlyAllowed
                        returns (uint256)
                    {
                        if (_chainIdChanged()) revert L1Forked();
                        // solhint-disable-next-line avoid-tx-origin
                        if (msg.sender != tx.origin) revert NotOrigin();
                        if (messageData.length > maxDataSize) revert DataTooLarge(messageData.length, maxDataSize);
                        uint256 msgNum = _deliverToBridge(L2_MSG, msg.sender, keccak256(messageData), 0);
                        emit InboxMessageDeliveredFromOrigin(msgNum);
                        return msgNum;
                    }
                    /// @inheritdoc IInboxBase
                    function sendL2Message(bytes calldata messageData)
                        external
                        whenNotPaused
                        onlyAllowed
                        returns (uint256)
                    {
                        if (_chainIdChanged()) revert L1Forked();
                        return _deliverMessage(L2_MSG, msg.sender, messageData, 0);
                    }
                    /// @inheritdoc IInboxBase
                    function sendUnsignedTransaction(
                        uint256 gasLimit,
                        uint256 maxFeePerGas,
                        uint256 nonce,
                        address to,
                        uint256 value,
                        bytes calldata data
                    ) external whenNotPaused onlyAllowed returns (uint256) {
                        // arbos will discard unsigned tx with gas limit too large
                        if (gasLimit > type(uint64).max) {
                            revert GasLimitTooLarge();
                        }
                        return
                            _deliverMessage(
                                L2_MSG,
                                msg.sender,
                                abi.encodePacked(
                                    L2MessageType_unsignedEOATx,
                                    gasLimit,
                                    maxFeePerGas,
                                    nonce,
                                    uint256(uint160(to)),
                                    value,
                                    data
                                ),
                                0
                            );
                    }
                    /// @inheritdoc IInboxBase
                    function sendContractTransaction(
                        uint256 gasLimit,
                        uint256 maxFeePerGas,
                        address to,
                        uint256 value,
                        bytes calldata data
                    ) external whenNotPaused onlyAllowed returns (uint256) {
                        // arbos will discard unsigned tx with gas limit too large
                        if (gasLimit > type(uint64).max) {
                            revert GasLimitTooLarge();
                        }
                        return
                            _deliverMessage(
                                L2_MSG,
                                msg.sender,
                                abi.encodePacked(
                                    L2MessageType_unsignedContractTx,
                                    gasLimit,
                                    maxFeePerGas,
                                    uint256(uint160(to)),
                                    value,
                                    data
                                ),
                                0
                            );
                    }
                    /// @inheritdoc IInboxBase
                    function getProxyAdmin() external view returns (address) {
                        return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
                    }
                    function _createRetryableTicket(
                        address to,
                        uint256 l2CallValue,
                        uint256 maxSubmissionCost,
                        address excessFeeRefundAddress,
                        address callValueRefundAddress,
                        uint256 gasLimit,
                        uint256 maxFeePerGas,
                        uint256 amount,
                        bytes calldata data
                    ) internal returns (uint256) {
                        // ensure the user's deposit alone will make submission succeed
                        if (amount < (maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas)) {
                            revert InsufficientValue(
                                maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas,
                                amount
                            );
                        }
                        // if a refund address is a contract, we apply the alias to it
                        // so that it can access its funds on the L2
                        // since the beneficiary and other refund addresses don't get rewritten by arb-os
                        if (AddressUpgradeable.isContract(excessFeeRefundAddress)) {
                            excessFeeRefundAddress = AddressAliasHelper.applyL1ToL2Alias(excessFeeRefundAddress);
                        }
                        if (AddressUpgradeable.isContract(callValueRefundAddress)) {
                            // this is the beneficiary. be careful since this is the address that can cancel the retryable in the L2
                            callValueRefundAddress = AddressAliasHelper.applyL1ToL2Alias(callValueRefundAddress);
                        }
                        // gas limit is validated to be within uint64 in unsafeCreateRetryableTicket
                        return
                            _unsafeCreateRetryableTicket(
                                to,
                                l2CallValue,
                                maxSubmissionCost,
                                excessFeeRefundAddress,
                                callValueRefundAddress,
                                gasLimit,
                                maxFeePerGas,
                                amount,
                                data
                            );
                    }
                    function _unsafeCreateRetryableTicket(
                        address to,
                        uint256 l2CallValue,
                        uint256 maxSubmissionCost,
                        address excessFeeRefundAddress,
                        address callValueRefundAddress,
                        uint256 gasLimit,
                        uint256 maxFeePerGas,
                        uint256 amount,
                        bytes calldata data
                    ) internal returns (uint256) {
                        // gas price and limit of 1 should never be a valid input, so instead they are used as
                        // magic values to trigger a revert in eth calls that surface data without requiring a tx trace
                        if (gasLimit == 1 || maxFeePerGas == 1)
                            revert RetryableData(
                                msg.sender,
                                to,
                                l2CallValue,
                                amount,
                                maxSubmissionCost,
                                excessFeeRefundAddress,
                                callValueRefundAddress,
                                gasLimit,
                                maxFeePerGas,
                                data
                            );
                        // arbos will discard retryable with gas limit too large
                        if (gasLimit > type(uint64).max) {
                            revert GasLimitTooLarge();
                        }
                        uint256 submissionFee = calculateRetryableSubmissionFee(data.length, block.basefee);
                        if (maxSubmissionCost < submissionFee)
                            revert InsufficientSubmissionCost(submissionFee, maxSubmissionCost);
                        return
                            _deliverMessage(
                                L1MessageType_submitRetryableTx,
                                msg.sender,
                                abi.encodePacked(
                                    uint256(uint160(to)),
                                    l2CallValue,
                                    amount,
                                    maxSubmissionCost,
                                    uint256(uint160(excessFeeRefundAddress)),
                                    uint256(uint160(callValueRefundAddress)),
                                    gasLimit,
                                    maxFeePerGas,
                                    data.length,
                                    data
                                ),
                                amount
                            );
                    }
                    function _deliverMessage(
                        uint8 _kind,
                        address _sender,
                        bytes memory _messageData,
                        uint256 amount
                    ) internal returns (uint256) {
                        if (_messageData.length > maxDataSize)
                            revert DataTooLarge(_messageData.length, maxDataSize);
                        uint256 msgNum = _deliverToBridge(_kind, _sender, keccak256(_messageData), amount);
                        emit InboxMessageDelivered(msgNum, _messageData);
                        return msgNum;
                    }
                    function _deliverToBridge(
                        uint8 kind,
                        address sender,
                        bytes32 messageDataHash,
                        uint256 amount
                    ) internal virtual returns (uint256);
                    function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
                        public
                        view
                        virtual
                        returns (uint256);
                    /**
                     * @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[47] private __gap;
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/nitro/blob/master/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.4;
                import "./AbsInbox.sol";
                import "./IERC20Inbox.sol";
                import "./IERC20Bridge.sol";
                import "../libraries/AddressAliasHelper.sol";
                import {L1MessageType_ethDeposit} from "../libraries/MessageTypes.sol";
                import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
                import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
                import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
                /**
                 * @title Inbox for user and contract originated messages
                 * @notice Messages created via this inbox are enqueued in the delayed accumulator
                 * to await inclusion in the SequencerInbox
                 */
                contract ERC20Inbox is AbsInbox, IERC20Inbox {
                    using SafeERC20 for IERC20;
                    constructor(uint256 _maxDataSize) AbsInbox(_maxDataSize) {}
                    /// @inheritdoc IInboxBase
                    function initialize(IBridge _bridge, ISequencerInbox _sequencerInbox)
                        external
                        initializer
                        onlyDelegated
                    {
                        __AbsInbox_init(_bridge, _sequencerInbox);
                        // inbox holds native token in transit used to pay for retryable tickets, approve bridge to use it
                        address nativeToken = IERC20Bridge(address(bridge)).nativeToken();
                        IERC20(nativeToken).approve(address(bridge), type(uint256).max);
                    }
                    /// @inheritdoc IERC20Inbox
                    function depositERC20(uint256 amount) public whenNotPaused onlyAllowed returns (uint256) {
                        address dest = msg.sender;
                        // solhint-disable-next-line avoid-tx-origin
                        if (AddressUpgradeable.isContract(msg.sender) || tx.origin != msg.sender) {
                            // isContract check fails if this function is called during a contract's constructor.
                            dest = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
                        }
                        return
                            _deliverMessage(
                                L1MessageType_ethDeposit,
                                msg.sender,
                                abi.encodePacked(dest, amount),
                                amount
                            );
                    }
                    /// @inheritdoc IERC20Inbox
                    function createRetryableTicket(
                        address to,
                        uint256 l2CallValue,
                        uint256 maxSubmissionCost,
                        address excessFeeRefundAddress,
                        address callValueRefundAddress,
                        uint256 gasLimit,
                        uint256 maxFeePerGas,
                        uint256 tokenTotalFeeAmount,
                        bytes calldata data
                    ) external whenNotPaused onlyAllowed returns (uint256) {
                        return
                            _createRetryableTicket(
                                to,
                                l2CallValue,
                                maxSubmissionCost,
                                excessFeeRefundAddress,
                                callValueRefundAddress,
                                gasLimit,
                                maxFeePerGas,
                                tokenTotalFeeAmount,
                                data
                            );
                    }
                    /// @inheritdoc IERC20Inbox
                    function unsafeCreateRetryableTicket(
                        address to,
                        uint256 l2CallValue,
                        uint256 maxSubmissionCost,
                        address excessFeeRefundAddress,
                        address callValueRefundAddress,
                        uint256 gasLimit,
                        uint256 maxFeePerGas,
                        uint256 tokenTotalFeeAmount,
                        bytes calldata data
                    ) public whenNotPaused onlyAllowed returns (uint256) {
                        return
                            _unsafeCreateRetryableTicket(
                                to,
                                l2CallValue,
                                maxSubmissionCost,
                                excessFeeRefundAddress,
                                callValueRefundAddress,
                                gasLimit,
                                maxFeePerGas,
                                tokenTotalFeeAmount,
                                data
                            );
                    }
                    /// @inheritdoc IInboxBase
                    function calculateRetryableSubmissionFee(uint256, uint256)
                        public
                        pure
                        override(AbsInbox, IInboxBase)
                        returns (uint256)
                    {
                        // retryable ticket's submission fee is not charged when ERC20 token is used to pay for fees
                        return 0;
                    }
                    function _deliverToBridge(
                        uint8 kind,
                        address sender,
                        bytes32 messageDataHash,
                        uint256 tokenAmount
                    ) internal override returns (uint256) {
                        // Fetch native token from sender if inbox doesn't already hold enough tokens to pay for fees.
                        // Inbox might have been pre-funded in prior call, ie. as part of token bridging flow.
                        address nativeToken = IERC20Bridge(address(bridge)).nativeToken();
                        uint256 inboxNativeTokenBalance = IERC20(nativeToken).balanceOf(address(this));
                        if (inboxNativeTokenBalance < tokenAmount) {
                            uint256 diff = tokenAmount - inboxNativeTokenBalance;
                            IERC20(nativeToken).safeTransferFrom(msg.sender, address(this), diff);
                        }
                        return
                            IERC20Bridge(address(bridge)).enqueueDelayedMessage(
                                kind,
                                AddressAliasHelper.applyL1ToL2Alias(sender),
                                messageDataHash,
                                tokenAmount
                            );
                    }
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.6.9 <0.9.0;
                import "./IOwnable.sol";
                interface IBridge {
                    event MessageDelivered(
                        uint256 indexed messageIndex,
                        bytes32 indexed beforeInboxAcc,
                        address inbox,
                        uint8 kind,
                        address sender,
                        bytes32 messageDataHash,
                        uint256 baseFeeL1,
                        uint64 timestamp
                    );
                    event BridgeCallTriggered(
                        address indexed outbox,
                        address indexed to,
                        uint256 value,
                        bytes data
                    );
                    event InboxToggle(address indexed inbox, bool enabled);
                    event OutboxToggle(address indexed outbox, bool enabled);
                    event SequencerInboxUpdated(address newSequencerInbox);
                    event RollupUpdated(address rollup);
                    function allowedDelayedInboxList(uint256) external returns (address);
                    function allowedOutboxList(uint256) external returns (address);
                    /// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
                    function delayedInboxAccs(uint256) external view returns (bytes32);
                    /// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
                    function sequencerInboxAccs(uint256) external view returns (bytes32);
                    function rollup() external view returns (IOwnable);
                    function sequencerInbox() external view returns (address);
                    function activeOutbox() external view returns (address);
                    function allowedDelayedInboxes(address inbox) external view returns (bool);
                    function allowedOutboxes(address outbox) external view returns (bool);
                    function sequencerReportedSubMessageCount() external view returns (uint256);
                    function executeCall(
                        address to,
                        uint256 value,
                        bytes calldata data
                    ) external returns (bool success, bytes memory returnData);
                    function delayedMessageCount() external view returns (uint256);
                    function sequencerMessageCount() external view returns (uint256);
                    // ---------- onlySequencerInbox functions ----------
                    function enqueueSequencerMessage(
                        bytes32 dataHash,
                        uint256 afterDelayedMessagesRead,
                        uint256 prevMessageCount,
                        uint256 newMessageCount
                    )
                        external
                        returns (
                            uint256 seqMessageIndex,
                            bytes32 beforeAcc,
                            bytes32 delayedAcc,
                            bytes32 acc
                        );
                    /**
                     * @dev Allows the sequencer inbox to submit a delayed message of the batchPostingReport type
                     *      This is done through a separate function entrypoint instead of allowing the sequencer inbox
                     *      to call `enqueueDelayedMessage` to avoid the gas overhead of an extra SLOAD in either
                     *      every delayed inbox or every sequencer inbox call.
                     */
                    function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
                        external
                        returns (uint256 msgNum);
                    // ---------- onlyRollupOrOwner functions ----------
                    function setSequencerInbox(address _sequencerInbox) external;
                    function setDelayedInbox(address inbox, bool enabled) external;
                    function setOutbox(address inbox, bool enabled) external;
                    function updateRollupAddress(IOwnable _rollup) external;
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.6.9 <0.9.0;
                interface IDelayedMessageProvider {
                    /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator
                    event InboxMessageDelivered(uint256 indexed messageNum, bytes data);
                    /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator
                    /// same as InboxMessageDelivered but the batch data is available in tx.input
                    event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum);
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/nitro/blob/master/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.6.9 <0.9.0;
                import "./IOwnable.sol";
                import "./IBridge.sol";
                interface IERC20Bridge is IBridge {
                    /**
                     * @dev token that is escrowed in bridge on L1 side and minted on L2 as native currency.
                     * Fees are paid in this token. There are certain restrictions on the native token:
                     *  - The token can't be rebasing or have a transfer fee
                     *  - The token must only be transferrable via a call to the token address itself
                     *  - The token must only be able to set allowance via a call to the token address itself
                     *  - The token must not have a callback on transfer, and more generally a user must not be able to make a transfer to themselves revert
                     */
                    function nativeToken() external view returns (address);
                    /**
                     * @dev Enqueue a message in the delayed inbox accumulator.
                     *      These messages are later sequenced in the SequencerInbox, either
                     *      by the sequencer as part of a normal batch, or by force inclusion.
                     */
                    function enqueueDelayedMessage(
                        uint8 kind,
                        address sender,
                        bytes32 messageDataHash,
                        uint256 tokenFeeAmount
                    ) external returns (uint256);
                    // ---------- initializer ----------
                    function initialize(IOwnable rollup_, address nativeToken_) external;
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/nitro/blob/master/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.6.9 <0.9.0;
                import "./IInboxBase.sol";
                interface IERC20Inbox is IInboxBase {
                    /**
                     * @notice Deposit native token from L1 to L2 to address of the sender if sender is an EOA, and to its aliased address if the sender is a contract
                     * @dev This does not trigger the fallback function when receiving in the L2 side.
                     *      Look into retryable tickets if you are interested in this functionality.
                     * @dev This function should not be called inside contract constructors
                     */
                    function depositERC20(uint256 amount) external returns (uint256);
                    /**
                     * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
                     * @dev all tokenTotalFeeAmount will be deposited to callValueRefundAddress on L2
                     * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
                     * @param to destination L2 contract address
                     * @param l2CallValue call value for retryable L2 message
                     * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
                     * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
                     * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
                     * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
                     * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
                     * @param tokenTotalFeeAmount amount of fees to be deposited in native token to cover for retryable ticket cost
                     * @param data ABI encoded data of L2 message
                     * @return unique message number of the retryable transaction
                     */
                    function createRetryableTicket(
                        address to,
                        uint256 l2CallValue,
                        uint256 maxSubmissionCost,
                        address excessFeeRefundAddress,
                        address callValueRefundAddress,
                        uint256 gasLimit,
                        uint256 maxFeePerGas,
                        uint256 tokenTotalFeeAmount,
                        bytes calldata data
                    ) external returns (uint256);
                    /**
                     * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts
                     * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed funds
                     * come from the deposit alone, rather than falling back on the user's L2 balance
                     * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress).
                     * createRetryableTicket method is the recommended standard.
                     * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error
                     * @param to destination L2 contract address
                     * @param l2CallValue call value for retryable L2 message
                     * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee
                     * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance
                     * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled
                     * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
                     * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error)
                     * @param tokenTotalFeeAmount amount of fees to be deposited in native token to cover for retryable ticket cost
                     * @param data ABI encoded data of L2 message
                     * @return unique message number of the retryable transaction
                     */
                    function unsafeCreateRetryableTicket(
                        address to,
                        uint256 l2CallValue,
                        uint256 maxSubmissionCost,
                        address excessFeeRefundAddress,
                        address callValueRefundAddress,
                        uint256 gasLimit,
                        uint256 maxFeePerGas,
                        uint256 tokenTotalFeeAmount,
                        bytes calldata data
                    ) external returns (uint256);
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.6.9 <0.9.0;
                import "./IBridge.sol";
                import "./IDelayedMessageProvider.sol";
                import "./ISequencerInbox.sol";
                interface IInboxBase is IDelayedMessageProvider {
                    function bridge() external view returns (IBridge);
                    function sequencerInbox() external view returns (ISequencerInbox);
                    function maxDataSize() external view returns (uint256);
                    /**
                     * @notice Send a generic L2 message to the chain
                     * @dev This method is an optimization to avoid having to emit the entirety of the messageData in a log. Instead validators are expected to be able to parse the data from the transaction's input
                     * @param messageData Data of the message being sent
                     */
                    function sendL2MessageFromOrigin(bytes calldata messageData) external returns (uint256);
                    /**
                     * @notice Send a generic L2 message to the chain
                     * @dev This method can be used to send any type of message that doesn't require L1 validation
                     * @param messageData Data of the message being sent
                     */
                    function sendL2Message(bytes calldata messageData) external returns (uint256);
                    function sendUnsignedTransaction(
                        uint256 gasLimit,
                        uint256 maxFeePerGas,
                        uint256 nonce,
                        address to,
                        uint256 value,
                        bytes calldata data
                    ) external returns (uint256);
                    function sendContractTransaction(
                        uint256 gasLimit,
                        uint256 maxFeePerGas,
                        address to,
                        uint256 value,
                        bytes calldata data
                    ) external returns (uint256);
                    /**
                     * @notice Get the L1 fee for submitting a retryable
                     * @dev This fee can be paid by funds already in the L2 aliased address or by the current message value
                     * @dev This formula may change in the future, to future proof your code query this method instead of inlining!!
                     * @param dataLength The length of the retryable's calldata, in bytes
                     * @param baseFee The block basefee when the retryable is included in the chain, if 0 current block.basefee will be used
                     */
                    function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
                        external
                        view
                        returns (uint256);
                    // ---------- onlyRollupOrOwner functions ----------
                    /// @notice pauses all inbox functionality
                    function pause() external;
                    /// @notice unpauses all inbox functionality
                    function unpause() external;
                    /// @notice add or remove users from allowList
                    function setAllowList(address[] memory user, bool[] memory val) external;
                    /// @notice enable or disable allowList
                    function setAllowListEnabled(bool _allowListEnabled) external;
                    /// @notice check if user is in allowList
                    function isAllowed(address user) external view returns (bool);
                    /// @notice check if allowList is enabled
                    function allowListEnabled() external view returns (bool);
                    function initialize(IBridge _bridge, ISequencerInbox _sequencerInbox) external;
                    /// @notice returns the current admin
                    function getProxyAdmin() external view returns (address);
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.4.21 <0.9.0;
                interface IOwnable {
                    function owner() external view returns (address);
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.6.9 <0.9.0;
                pragma experimental ABIEncoderV2;
                import "../libraries/IGasRefunder.sol";
                import "./IDelayedMessageProvider.sol";
                import "./IBridge.sol";
                interface ISequencerInbox is IDelayedMessageProvider {
                    struct MaxTimeVariation {
                        uint256 delayBlocks;
                        uint256 futureBlocks;
                        uint256 delaySeconds;
                        uint256 futureSeconds;
                    }
                    struct TimeBounds {
                        uint64 minTimestamp;
                        uint64 maxTimestamp;
                        uint64 minBlockNumber;
                        uint64 maxBlockNumber;
                    }
                    enum BatchDataLocation {
                        TxInput,
                        SeparateBatchEvent,
                        NoData
                    }
                    event SequencerBatchDelivered(
                        uint256 indexed batchSequenceNumber,
                        bytes32 indexed beforeAcc,
                        bytes32 indexed afterAcc,
                        bytes32 delayedAcc,
                        uint256 afterDelayedMessagesRead,
                        TimeBounds timeBounds,
                        BatchDataLocation dataLocation
                    );
                    event OwnerFunctionCalled(uint256 indexed id);
                    /// @dev a separate event that emits batch data when this isn't easily accessible in the tx.input
                    event SequencerBatchData(uint256 indexed batchSequenceNumber, bytes data);
                    /// @dev a valid keyset was added
                    event SetValidKeyset(bytes32 indexed keysetHash, bytes keysetBytes);
                    /// @dev a keyset was invalidated
                    event InvalidateKeyset(bytes32 indexed keysetHash);
                    function totalDelayedMessagesRead() external view returns (uint256);
                    function bridge() external view returns (IBridge);
                    /// @dev The size of the batch header
                    // solhint-disable-next-line func-name-mixedcase
                    function HEADER_LENGTH() external view returns (uint256);
                    /// @dev If the first batch data byte after the header has this bit set,
                    ///      the sequencer inbox has authenticated the data. Currently not used.
                    // solhint-disable-next-line func-name-mixedcase
                    function DATA_AUTHENTICATED_FLAG() external view returns (bytes1);
                    function rollup() external view returns (IOwnable);
                    function isBatchPoster(address) external view returns (bool);
                    function isSequencer(address) external view returns (bool);
                    function maxDataSize() external view returns (uint256);
                    struct DasKeySetInfo {
                        bool isValidKeyset;
                        uint64 creationBlock;
                    }
                    function maxTimeVariation()
                        external
                        view
                        returns (
                            uint256,
                            uint256,
                            uint256,
                            uint256
                        );
                    function dasKeySetInfo(bytes32) external view returns (bool, uint64);
                    /// @notice Remove force inclusion delay after a L1 chainId fork
                    function removeDelayAfterFork() external;
                    /// @notice Force messages from the delayed inbox to be included in the chain
                    ///         Callable by any address, but message can only be force-included after maxTimeVariation.delayBlocks and
                    ///         maxTimeVariation.delaySeconds has elapsed. As part of normal behaviour the sequencer will include these
                    ///         messages so it's only necessary to call this if the sequencer is down, or not including any delayed messages.
                    /// @param _totalDelayedMessagesRead The total number of messages to read up to
                    /// @param kind The kind of the last message to be included
                    /// @param l1BlockAndTime The l1 block and the l1 timestamp of the last message to be included
                    /// @param baseFeeL1 The l1 gas price of the last message to be included
                    /// @param sender The sender of the last message to be included
                    /// @param messageDataHash The messageDataHash of the last message to be included
                    function forceInclusion(
                        uint256 _totalDelayedMessagesRead,
                        uint8 kind,
                        uint64[2] calldata l1BlockAndTime,
                        uint256 baseFeeL1,
                        address sender,
                        bytes32 messageDataHash
                    ) external;
                    function inboxAccs(uint256 index) external view returns (bytes32);
                    function batchCount() external view returns (uint256);
                    function isValidKeysetHash(bytes32 ksHash) external view returns (bool);
                    /// @notice the creation block is intended to still be available after a keyset is deleted
                    function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256);
                    // ---------- BatchPoster functions ----------
                    function addSequencerL2BatchFromOrigin(
                        uint256 sequenceNumber,
                        bytes calldata data,
                        uint256 afterDelayedMessagesRead,
                        IGasRefunder gasRefunder
                    ) external;
                    function addSequencerL2Batch(
                        uint256 sequenceNumber,
                        bytes calldata data,
                        uint256 afterDelayedMessagesRead,
                        IGasRefunder gasRefunder,
                        uint256 prevMessageCount,
                        uint256 newMessageCount
                    ) external;
                    // ---------- onlyRollupOrOwner functions ----------
                    /**
                     * @notice Set max delay for sequencer inbox
                     * @param maxTimeVariation_ the maximum time variation parameters
                     */
                    function setMaxTimeVariation(MaxTimeVariation memory maxTimeVariation_) external;
                    /**
                     * @notice Updates whether an address is authorized to be a batch poster at the sequencer inbox
                     * @param addr the address
                     * @param isBatchPoster_ if the specified address should be authorized as a batch poster
                     */
                    function setIsBatchPoster(address addr, bool isBatchPoster_) external;
                    /**
                     * @notice Makes Data Availability Service keyset valid
                     * @param keysetBytes bytes of the serialized keyset
                     */
                    function setValidKeyset(bytes calldata keysetBytes) external;
                    /**
                     * @notice Invalidates a Data Availability Service keyset
                     * @param ksHash hash of the keyset
                     */
                    function invalidateKeysetHash(bytes32 ksHash) external;
                    /**
                     * @notice Updates whether an address is authorized to be a sequencer.
                     * @dev The IsSequencer information is used only off-chain by the nitro node to validate sequencer feed signer.
                     * @param addr the address
                     * @param isSequencer_ if the specified address should be authorized as a sequencer
                     */
                    function setIsSequencer(address addr, bool isSequencer_) external;
                    // ---------- initializer ----------
                    function initialize(IBridge bridge_, MaxTimeVariation calldata maxTimeVariation_) external;
                    function updateRollupAddress() external;
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.0;
                library AddressAliasHelper {
                    uint160 internal constant OFFSET = uint160(0x1111000000000000000000000000000000001111);
                    /// @notice Utility function that converts the address in the L1 that submitted a tx to
                    /// the inbox to the msg.sender viewed in the L2
                    /// @param l1Address the address in the L1 that triggered the tx to L2
                    /// @return l2Address L2 address as viewed in msg.sender
                    function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
                        unchecked {
                            l2Address = address(uint160(l1Address) + OFFSET);
                        }
                    }
                    /// @notice Utility function that converts the msg.sender viewed in the L2 to the
                    /// address in the L1 that submitted a tx to the inbox
                    /// @param l2Address L2 address as viewed in msg.sender
                    /// @return l1Address the address in the L1 that triggered the tx to L2
                    function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
                        unchecked {
                            l1Address = address(uint160(l2Address) - OFFSET);
                        }
                    }
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.0;
                import {NotOwner} from "./Error.sol";
                /// @dev A stateless contract that allows you to infer if the current call has been delegated or not
                /// Pattern used here is from UUPS implementation by the OpenZeppelin team
                abstract contract DelegateCallAware {
                    address private immutable __self = address(this);
                    /**
                     * @dev Check that the execution is being performed through a delegate call. This allows a function to be
                     * callable on the proxy contract but not on the logic contract.
                     */
                    modifier onlyDelegated() {
                        require(address(this) != __self, "Function must be called through delegatecall");
                        _;
                    }
                    /**
                     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
                     * callable on the implementing contract but not through proxies.
                     */
                    modifier notDelegated() {
                        require(address(this) == __self, "Function must not be called through delegatecall");
                        _;
                    }
                    /// @dev Check that msg.sender is the current EIP 1967 proxy admin
                    modifier onlyProxyOwner() {
                        // Storage slot with the admin of the proxy contract
                        // This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1
                        bytes32 slot = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                        address admin;
                        assembly {
                            admin := sload(slot)
                        }
                        if (msg.sender != admin) revert NotOwner(msg.sender, admin);
                        _;
                    }
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.4;
                /// @dev Init was already called
                error AlreadyInit();
                /// @dev Init was called with param set to zero that must be nonzero
                error HadZeroInit();
                /// @dev Thrown when post upgrade init validation fails
                error BadPostUpgradeInit();
                /// @dev Thrown when non owner tries to access an only-owner function
                /// @param sender The msg.sender who is not the owner
                /// @param owner The owner address
                error NotOwner(address sender, address owner);
                /// @dev Thrown when an address that is not the rollup tries to call an only-rollup function
                /// @param sender The sender who is not the rollup
                /// @param rollup The rollup address authorized to call this function
                error NotRollup(address sender, address rollup);
                /// @dev Thrown when the contract was not called directly from the origin ie msg.sender != tx.origin
                error NotOrigin();
                /// @dev Provided data was too large
                /// @param dataLength The length of the data that is too large
                /// @param maxDataLength The max length the data can be
                error DataTooLarge(uint256 dataLength, uint256 maxDataLength);
                /// @dev The provided is not a contract and was expected to be
                /// @param addr The adddress in question
                error NotContract(address addr);
                /// @dev The merkle proof provided was too long
                /// @param actualLength The length of the merkle proof provided
                /// @param maxProofLength The max length a merkle proof can have
                error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength);
                /// @dev Thrown when an un-authorized address tries to access an admin function
                /// @param sender The un-authorized sender
                /// @param rollup The rollup, which would be authorized
                /// @param owner The rollup's owner, which would be authorized
                error NotRollupOrOwner(address sender, address rollup, address owner);
                // Bridge Errors
                /// @dev Thrown when an un-authorized address tries to access an only-inbox function
                /// @param sender The un-authorized sender
                error NotDelayedInbox(address sender);
                /// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function
                /// @param sender The un-authorized sender
                error NotSequencerInbox(address sender);
                /// @dev Thrown when an un-authorized address tries to access an only-outbox function
                /// @param sender The un-authorized sender
                error NotOutbox(address sender);
                /// @dev the provided outbox address isn't valid
                /// @param outbox address of outbox being set
                error InvalidOutboxSet(address outbox);
                /// @dev The provided token address isn't valid
                /// @param token address of token being set
                error InvalidTokenSet(address token);
                /// @dev Call to this specific address is not allowed
                /// @param target address of the call receiver
                error CallTargetNotAllowed(address target);
                /// @dev Call that changes the balance of ERC20Bridge is not allowed
                error CallNotAllowed();
                // Inbox Errors
                /// @dev The contract is paused, so cannot be paused
                error AlreadyPaused();
                /// @dev The contract is unpaused, so cannot be unpaused
                error AlreadyUnpaused();
                /// @dev The contract is paused
                error Paused();
                /// @dev msg.value sent to the inbox isn't high enough
                error InsufficientValue(uint256 expected, uint256 actual);
                /// @dev submission cost provided isn't enough to create retryable ticket
                error InsufficientSubmissionCost(uint256 expected, uint256 actual);
                /// @dev address not allowed to interact with the given contract
                error NotAllowedOrigin(address origin);
                /// @dev used to convey retryable tx data in eth calls without requiring a tx trace
                /// this follows a pattern similar to EIP-3668 where reverts surface call information
                error RetryableData(
                    address from,
                    address to,
                    uint256 l2CallValue,
                    uint256 deposit,
                    uint256 maxSubmissionCost,
                    address excessFeeRefundAddress,
                    address callValueRefundAddress,
                    uint256 gasLimit,
                    uint256 maxFeePerGas,
                    bytes data
                );
                /// @dev Thrown when a L1 chainId fork is detected
                error L1Forked();
                /// @dev Thrown when a L1 chainId fork is not detected
                error NotForked();
                /// @dev The provided gasLimit is larger than uint64
                error GasLimitTooLarge();
                // Outbox Errors
                /// @dev The provided proof was too long
                /// @param proofLength The length of the too-long proof
                error ProofTooLong(uint256 proofLength);
                /// @dev The output index was greater than the maximum
                /// @param index The output index
                /// @param maxIndex The max the index could be
                error PathNotMinimal(uint256 index, uint256 maxIndex);
                /// @dev The calculated root does not exist
                /// @param root The calculated root
                error UnknownRoot(bytes32 root);
                /// @dev The record has already been spent
                /// @param index The index of the spent record
                error AlreadySpent(uint256 index);
                /// @dev A call to the bridge failed with no return data
                error BridgeCallFailed();
                // Sequencer Inbox Errors
                /// @dev Thrown when someone attempts to read fewer messages than have already been read
                error DelayedBackwards();
                /// @dev Thrown when someone attempts to read more messages than exist
                error DelayedTooFar();
                /// @dev Force include can only read messages more blocks old than the delay period
                error ForceIncludeBlockTooSoon();
                /// @dev Force include can only read messages more seconds old than the delay period
                error ForceIncludeTimeTooSoon();
                /// @dev The message provided did not match the hash in the delayed inbox
                error IncorrectMessagePreimage();
                /// @dev This can only be called by the batch poster
                error NotBatchPoster();
                /// @dev The sequence number provided to this message was inconsistent with the number of batches already included
                error BadSequencerNumber(uint256 stored, uint256 received);
                /// @dev The sequence message number provided to this message was inconsistent with the previous one
                error BadSequencerMessageNumber(uint256 stored, uint256 received);
                /// @dev The batch data has the inbox authenticated bit set, but the batch data was not authenticated by the inbox
                error DataNotAuthenticated();
                /// @dev Tried to create an already valid Data Availability Service keyset
                error AlreadyValidDASKeyset(bytes32);
                /// @dev Tried to use or invalidate an already invalid Data Availability Service keyset
                error NoSuchKeyset(bytes32);
                /// @dev Thrown when rollup is not updated with updateRollupAddress
                error RollupNotChanged();
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.6.9 <0.9.0;
                interface IGasRefunder {
                    function onGasSpent(
                        address payable spender,
                        uint256 gasUsed,
                        uint256 calldataSize
                    ) external returns (bool success);
                }
                abstract contract GasRefundEnabled {
                    /// @dev this refunds the sender for execution costs of the tx
                    /// calldata costs are only refunded if `msg.sender == tx.origin` to guarantee the value refunded relates to charging
                    /// for the `tx.input`. this avoids a possible attack where you generate large calldata from a contract and get over-refunded
                    modifier refundsGas(IGasRefunder gasRefunder) {
                        uint256 startGasLeft = gasleft();
                        _;
                        if (address(gasRefunder) != address(0)) {
                            uint256 calldataSize = msg.data.length;
                            uint256 calldataWords = (calldataSize + 31) / 32;
                            // account for the CALLDATACOPY cost of the proxy contract, including the memory expansion cost
                            startGasLeft += calldataWords * 6 + (calldataWords**2) / 512;
                            // if triggered in a contract call, the spender may be overrefunded by appending dummy data to the call
                            // so we check if it is a top level call, which would mean the sender paid calldata as part of tx.input
                            // solhint-disable-next-line avoid-tx-origin
                            if (msg.sender != tx.origin) {
                                // We can't be sure if this calldata came from the top level tx,
                                // so to be safe we tell the gas refunder there was no calldata.
                                calldataSize = 0;
                            }
                            gasRefunder.onGasSpent(payable(msg.sender), startGasLeft - gasleft(), calldataSize);
                        }
                    }
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.4;
                uint8 constant L2_MSG = 3;
                uint8 constant L1MessageType_L2FundedByL1 = 7;
                uint8 constant L1MessageType_submitRetryableTx = 9;
                uint8 constant L1MessageType_ethDeposit = 12;
                uint8 constant L1MessageType_batchPostingReport = 13;
                uint8 constant L2MessageType_unsignedEOATx = 0;
                uint8 constant L2MessageType_unsignedContractTx = 1;
                uint8 constant ROLLUP_PROTOCOL_EVENT_TYPE = 8;
                uint8 constant INITIALIZATION_MSG_TYPE = 11;
                

                File 6 of 6: ERC20Bridge
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)
                pragma solidity ^0.8.0;
                import "../../utils/AddressUpgradeable.sol";
                /**
                 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
                 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                 *
                 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                 *
                 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                 *
                 * [CAUTION]
                 * ====
                 * Avoid leaving a contract uninitialized.
                 *
                 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
                 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
                 *
                 * [.hljs-theme-light.nopadding]
                 * ```
                 * /// @custom:oz-upgrades-unsafe-allow constructor
                 * constructor() initializer {}
                 * ```
                 * ====
                 */
                abstract contract Initializable {
                    /**
                     * @dev Indicates that the contract has been initialized.
                     */
                    bool private _initialized;
                    /**
                     * @dev Indicates that the contract is in the process of being initialized.
                     */
                    bool private _initializing;
                    /**
                     * @dev Modifier to protect an initializer function from being invoked twice.
                     */
                    modifier initializer() {
                        // If the contract is initializing we ignore whether _initialized is set in order to support multiple
                        // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
                        // contract may have been reentered.
                        require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");
                        bool isTopLevelCall = !_initializing;
                        if (isTopLevelCall) {
                            _initializing = true;
                            _initialized = true;
                        }
                        _;
                        if (isTopLevelCall) {
                            _initializing = false;
                        }
                    }
                    /**
                     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                     * {initializer} modifier, directly or indirectly.
                     */
                    modifier onlyInitializing() {
                        require(_initializing, "Initializable: contract is not initializing");
                        _;
                    }
                    function _isConstructor() private view returns (bool) {
                        return !AddressUpgradeable.isContract(address(this));
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
                pragma solidity ^0.8.1;
                /**
                 * @dev Collection of functions related to the address type
                 */
                library AddressUpgradeable {
                    /**
                     * @dev Returns true if `account` is a contract.
                     *
                     * [IMPORTANT]
                     * ====
                     * It is unsafe to assume that an address for which this function returns
                     * false is an externally-owned account (EOA) and not a contract.
                     *
                     * Among others, `isContract` will return false for the following
                     * types of addresses:
                     *
                     *  - an externally-owned account
                     *  - a contract in construction
                     *  - an address where a contract will be created
                     *  - an address where a contract lived, but was destroyed
                     * ====
                     *
                     * [IMPORTANT]
                     * ====
                     * You shouldn't rely on `isContract` to protect against flash loan attacks!
                     *
                     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                     * constructor.
                     * ====
                     */
                    function isContract(address account) internal view returns (bool) {
                        // This method relies on extcodesize/address.code.length, which returns 0
                        // for contracts in construction, since the code is only stored at the end
                        // of the constructor execution.
                        return account.code.length > 0;
                    }
                    /**
                     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                     * `recipient`, forwarding all available gas and reverting on errors.
                     *
                     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                     * of certain opcodes, possibly making contracts go over the 2300 gas limit
                     * imposed by `transfer`, making them unable to receive funds via
                     * `transfer`. {sendValue} removes this limitation.
                     *
                     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                     *
                     * IMPORTANT: because control is transferred to `recipient`, care must be
                     * taken to not create reentrancy vulnerabilities. Consider using
                     * {ReentrancyGuard} or the
                     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                     */
                    function sendValue(address payable recipient, uint256 amount) internal {
                        require(address(this).balance >= amount, "Address: insufficient balance");
                        (bool success, ) = recipient.call{value: amount}("");
                        require(success, "Address: unable to send value, recipient may have reverted");
                    }
                    /**
                     * @dev Performs a Solidity function call using a low level `call`. A
                     * plain `call` is an unsafe replacement for a function call: use this
                     * function instead.
                     *
                     * If `target` reverts with a revert reason, it is bubbled up by this
                     * function (like regular Solidity function calls).
                     *
                     * Returns the raw returned data. To convert to the expected return value,
                     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                     *
                     * Requirements:
                     *
                     * - `target` must be a contract.
                     * - calling `target` with `data` must not revert.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionCall(target, data, "Address: low-level call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                     * `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, 0, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but also transferring `value` wei to `target`.
                     *
                     * Requirements:
                     *
                     * - the calling contract must have an ETH balance of at least `value`.
                     * - the called Solidity function must be `payable`.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                     * with `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(address(this).balance >= value, "Address: insufficient balance for call");
                        require(isContract(target), "Address: call to non-contract");
                        (bool success, bytes memory returndata) = target.call{value: value}(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                        return functionStaticCall(target, data, "Address: low-level static call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal view returns (bytes memory) {
                        require(isContract(target), "Address: static call to non-contract");
                        (bool success, bytes memory returndata) = target.staticcall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                     * revert reason using the provided one.
                     *
                     * _Available since v4.3._
                     */
                    function verifyCallResult(
                        bool success,
                        bytes memory returndata,
                        string memory errorMessage
                    ) internal pure returns (bytes memory) {
                        if (success) {
                            return returndata;
                        } else {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert(errorMessage);
                            }
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)
                pragma solidity ^0.8.0;
                /**
                 * @dev Interface of the ERC20 standard as defined in the EIP.
                 */
                interface IERC20 {
                    /**
                     * @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);
                    /**
                     * @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);
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
                pragma solidity ^0.8.0;
                import "../IERC20.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;
                    function safeTransfer(
                        IERC20 token,
                        address to,
                        uint256 value
                    ) internal {
                        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                    }
                    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));
                    }
                    function safeIncreaseAllowance(
                        IERC20 token,
                        address spender,
                        uint256 value
                    ) internal {
                        uint256 newAllowance = token.allowance(address(this), spender) + value;
                        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                    }
                    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");
                            uint256 newAllowance = oldAllowance - value;
                            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                        }
                    }
                    /**
                     * @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");
                        if (returndata.length > 0) {
                            // Return data is optional
                            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                        }
                    }
                }
                // SPDX-License-Identifier: MIT
                // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
                pragma solidity ^0.8.1;
                /**
                 * @dev Collection of functions related to the address type
                 */
                library Address {
                    /**
                     * @dev Returns true if `account` is a contract.
                     *
                     * [IMPORTANT]
                     * ====
                     * It is unsafe to assume that an address for which this function returns
                     * false is an externally-owned account (EOA) and not a contract.
                     *
                     * Among others, `isContract` will return false for the following
                     * types of addresses:
                     *
                     *  - an externally-owned account
                     *  - a contract in construction
                     *  - an address where a contract will be created
                     *  - an address where a contract lived, but was destroyed
                     * ====
                     *
                     * [IMPORTANT]
                     * ====
                     * You shouldn't rely on `isContract` to protect against flash loan attacks!
                     *
                     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                     * constructor.
                     * ====
                     */
                    function isContract(address account) internal view returns (bool) {
                        // This method relies on extcodesize/address.code.length, which returns 0
                        // for contracts in construction, since the code is only stored at the end
                        // of the constructor execution.
                        return account.code.length > 0;
                    }
                    /**
                     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                     * `recipient`, forwarding all available gas and reverting on errors.
                     *
                     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                     * of certain opcodes, possibly making contracts go over the 2300 gas limit
                     * imposed by `transfer`, making them unable to receive funds via
                     * `transfer`. {sendValue} removes this limitation.
                     *
                     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                     *
                     * IMPORTANT: because control is transferred to `recipient`, care must be
                     * taken to not create reentrancy vulnerabilities. Consider using
                     * {ReentrancyGuard} or the
                     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                     */
                    function sendValue(address payable recipient, uint256 amount) internal {
                        require(address(this).balance >= amount, "Address: insufficient balance");
                        (bool success, ) = recipient.call{value: amount}("");
                        require(success, "Address: unable to send value, recipient may have reverted");
                    }
                    /**
                     * @dev Performs a Solidity function call using a low level `call`. A
                     * plain `call` is an unsafe replacement for a function call: use this
                     * function instead.
                     *
                     * If `target` reverts with a revert reason, it is bubbled up by this
                     * function (like regular Solidity function calls).
                     *
                     * Returns the raw returned data. To convert to the expected return value,
                     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                     *
                     * Requirements:
                     *
                     * - `target` must be a contract.
                     * - calling `target` with `data` must not revert.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionCall(target, data, "Address: low-level call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                     * `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, 0, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but also transferring `value` wei to `target`.
                     *
                     * Requirements:
                     *
                     * - the calling contract must have an ETH balance of at least `value`.
                     * - the called Solidity function must be `payable`.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value
                    ) internal returns (bytes memory) {
                        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                     * with `errorMessage` as a fallback revert reason when `target` reverts.
                     *
                     * _Available since v3.1._
                     */
                    function functionCallWithValue(
                        address target,
                        bytes memory data,
                        uint256 value,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(address(this).balance >= value, "Address: insufficient balance for call");
                        require(isContract(target), "Address: call to non-contract");
                        (bool success, bytes memory returndata) = target.call{value: value}(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                        return functionStaticCall(target, data, "Address: low-level static call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a static call.
                     *
                     * _Available since v3.3._
                     */
                    function functionStaticCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal view returns (bytes memory) {
                        require(isContract(target), "Address: static call to non-contract");
                        (bool success, bytes memory returndata) = target.staticcall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                     * but performing a delegate call.
                     *
                     * _Available since v3.4._
                     */
                    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                    }
                    /**
                     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                     * but performing a delegate call.
                     *
                     * _Available since v3.4._
                     */
                    function functionDelegateCall(
                        address target,
                        bytes memory data,
                        string memory errorMessage
                    ) internal returns (bytes memory) {
                        require(isContract(target), "Address: delegate call to non-contract");
                        (bool success, bytes memory returndata) = target.delegatecall(data);
                        return verifyCallResult(success, returndata, errorMessage);
                    }
                    /**
                     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                     * revert reason using the provided one.
                     *
                     * _Available since v4.3._
                     */
                    function verifyCallResult(
                        bool success,
                        bytes memory returndata,
                        string memory errorMessage
                    ) internal pure returns (bytes memory) {
                        if (success) {
                            return returndata;
                        } else {
                            // Look for revert reason and bubble it up if present
                            if (returndata.length > 0) {
                                // The easiest way to bubble the revert reason is using memory via assembly
                                assembly {
                                    let returndata_size := mload(returndata)
                                    revert(add(32, returndata), returndata_size)
                                }
                            } else {
                                revert(errorMessage);
                            }
                        }
                    }
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/nitro/blob/master/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.4;
                import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
                import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
                import {
                    NotContract,
                    NotRollupOrOwner,
                    NotDelayedInbox,
                    NotSequencerInbox,
                    NotOutbox,
                    InvalidOutboxSet,
                    BadSequencerMessageNumber
                } from "../libraries/Error.sol";
                import "./IBridge.sol";
                import "./Messages.sol";
                import "../libraries/DelegateCallAware.sol";
                import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol";
                /**
                 * @title Staging ground for incoming and outgoing messages
                 * @notice Holds the inbox accumulator for sequenced and delayed messages.
                 * Since the escrow is held here, this contract also contains a list of allowed
                 * outboxes that can make calls from here and withdraw this escrow.
                 */
                abstract contract AbsBridge is Initializable, DelegateCallAware, IBridge {
                    using AddressUpgradeable for address;
                    struct InOutInfo {
                        uint256 index;
                        bool allowed;
                    }
                    mapping(address => InOutInfo) private allowedDelayedInboxesMap;
                    mapping(address => InOutInfo) private allowedOutboxesMap;
                    address[] public allowedDelayedInboxList;
                    address[] public allowedOutboxList;
                    address internal _activeOutbox;
                    /// @inheritdoc IBridge
                    bytes32[] public delayedInboxAccs;
                    /// @inheritdoc IBridge
                    bytes32[] public sequencerInboxAccs;
                    IOwnable public rollup;
                    address public sequencerInbox;
                    uint256 public override sequencerReportedSubMessageCount;
                    address internal constant EMPTY_ACTIVEOUTBOX = address(type(uint160).max);
                    modifier onlyRollupOrOwner() {
                        if (msg.sender != address(rollup)) {
                            address rollupOwner = rollup.owner();
                            if (msg.sender != rollupOwner) {
                                revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
                            }
                        }
                        _;
                    }
                    /// @notice Allows the rollup owner to set another rollup address
                    function updateRollupAddress(IOwnable _rollup) external onlyRollupOrOwner {
                        rollup = _rollup;
                        emit RollupUpdated(address(_rollup));
                    }
                    /// @dev returns the address of current active Outbox, or zero if no outbox is active
                    function activeOutbox() public view returns (address) {
                        address outbox = _activeOutbox;
                        // address zero is returned if no outbox is set, but the value used in storage
                        // is non-zero to save users some gas (as storage refunds are usually maxed out)
                        // EIP-1153 would help here.
                        // we don't return `EMPTY_ACTIVEOUTBOX` to avoid a breaking change on the current api
                        if (outbox == EMPTY_ACTIVEOUTBOX) return address(0);
                        return outbox;
                    }
                    function allowedDelayedInboxes(address inbox) public view returns (bool) {
                        return allowedDelayedInboxesMap[inbox].allowed;
                    }
                    function allowedOutboxes(address outbox) public view returns (bool) {
                        return allowedOutboxesMap[outbox].allowed;
                    }
                    modifier onlySequencerInbox() {
                        if (msg.sender != sequencerInbox) revert NotSequencerInbox(msg.sender);
                        _;
                    }
                    function enqueueSequencerMessage(
                        bytes32 dataHash,
                        uint256 afterDelayedMessagesRead,
                        uint256 prevMessageCount,
                        uint256 newMessageCount
                    )
                        external
                        onlySequencerInbox
                        returns (
                            uint256 seqMessageIndex,
                            bytes32 beforeAcc,
                            bytes32 delayedAcc,
                            bytes32 acc
                        )
                    {
                        if (
                            sequencerReportedSubMessageCount != prevMessageCount &&
                            prevMessageCount != 0 &&
                            sequencerReportedSubMessageCount != 0
                        ) {
                            revert BadSequencerMessageNumber(sequencerReportedSubMessageCount, prevMessageCount);
                        }
                        sequencerReportedSubMessageCount = newMessageCount;
                        seqMessageIndex = sequencerInboxAccs.length;
                        if (sequencerInboxAccs.length > 0) {
                            beforeAcc = sequencerInboxAccs[sequencerInboxAccs.length - 1];
                        }
                        if (afterDelayedMessagesRead > 0) {
                            delayedAcc = delayedInboxAccs[afterDelayedMessagesRead - 1];
                        }
                        acc = keccak256(abi.encodePacked(beforeAcc, dataHash, delayedAcc));
                        sequencerInboxAccs.push(acc);
                    }
                    /// @inheritdoc IBridge
                    function submitBatchSpendingReport(address sender, bytes32 messageDataHash)
                        external
                        onlySequencerInbox
                        returns (uint256)
                    {
                        return
                            addMessageToDelayedAccumulator(
                                L1MessageType_batchPostingReport,
                                sender,
                                uint64(block.number),
                                uint64(block.timestamp), // solhint-disable-line not-rely-on-time,
                                block.basefee,
                                messageDataHash
                            );
                    }
                    function _enqueueDelayedMessage(
                        uint8 kind,
                        address sender,
                        bytes32 messageDataHash,
                        uint256 amount
                    ) internal returns (uint256) {
                        if (!allowedDelayedInboxes(msg.sender)) revert NotDelayedInbox(msg.sender);
                        uint256 messageCount = addMessageToDelayedAccumulator(
                            kind,
                            sender,
                            uint64(block.number),
                            uint64(block.timestamp), // solhint-disable-line not-rely-on-time
                            _baseFeeToReport(),
                            messageDataHash
                        );
                        _transferFunds(amount);
                        return messageCount;
                    }
                    function addMessageToDelayedAccumulator(
                        uint8 kind,
                        address sender,
                        uint64 blockNumber,
                        uint64 blockTimestamp,
                        uint256 baseFeeL1,
                        bytes32 messageDataHash
                    ) internal returns (uint256) {
                        uint256 count = delayedInboxAccs.length;
                        bytes32 messageHash = Messages.messageHash(
                            kind,
                            sender,
                            blockNumber,
                            blockTimestamp,
                            count,
                            baseFeeL1,
                            messageDataHash
                        );
                        bytes32 prevAcc = 0;
                        if (count > 0) {
                            prevAcc = delayedInboxAccs[count - 1];
                        }
                        delayedInboxAccs.push(Messages.accumulateInboxMessage(prevAcc, messageHash));
                        emit MessageDelivered(
                            count,
                            prevAcc,
                            msg.sender,
                            kind,
                            sender,
                            messageDataHash,
                            baseFeeL1,
                            blockTimestamp
                        );
                        return count;
                    }
                    /// @inheritdoc IBridge
                    function executeCall(
                        address to,
                        uint256 value,
                        bytes calldata data
                    ) external returns (bool success, bytes memory returnData) {
                        if (!allowedOutboxes(msg.sender)) revert NotOutbox(msg.sender);
                        if (data.length > 0 && !to.isContract()) revert NotContract(to);
                        address prevOutbox = _activeOutbox;
                        _activeOutbox = msg.sender;
                        // We set and reset active outbox around external call so activeOutbox remains valid during call
                        // We use a low level call here since we want to bubble up whether it succeeded or failed to the caller
                        // rather than reverting on failure as well as allow contract and non-contract calls
                        (success, returnData) = _executeLowLevelCall(to, value, data);
                        _activeOutbox = prevOutbox;
                        emit BridgeCallTriggered(msg.sender, to, value, data);
                    }
                    function setSequencerInbox(address _sequencerInbox) external onlyRollupOrOwner {
                        sequencerInbox = _sequencerInbox;
                        emit SequencerInboxUpdated(_sequencerInbox);
                    }
                    function setDelayedInbox(address inbox, bool enabled) external onlyRollupOrOwner {
                        InOutInfo storage info = allowedDelayedInboxesMap[inbox];
                        bool alreadyEnabled = info.allowed;
                        emit InboxToggle(inbox, enabled);
                        if (alreadyEnabled == enabled) {
                            return;
                        }
                        if (enabled) {
                            allowedDelayedInboxesMap[inbox] = InOutInfo(allowedDelayedInboxList.length, true);
                            allowedDelayedInboxList.push(inbox);
                        } else {
                            allowedDelayedInboxList[info.index] = allowedDelayedInboxList[
                                allowedDelayedInboxList.length - 1
                            ];
                            allowedDelayedInboxesMap[allowedDelayedInboxList[info.index]].index = info.index;
                            allowedDelayedInboxList.pop();
                            delete allowedDelayedInboxesMap[inbox];
                        }
                    }
                    function setOutbox(address outbox, bool enabled) external onlyRollupOrOwner {
                        if (outbox == EMPTY_ACTIVEOUTBOX) revert InvalidOutboxSet(outbox);
                        InOutInfo storage info = allowedOutboxesMap[outbox];
                        bool alreadyEnabled = info.allowed;
                        emit OutboxToggle(outbox, enabled);
                        if (alreadyEnabled == enabled) {
                            return;
                        }
                        if (enabled) {
                            allowedOutboxesMap[outbox] = InOutInfo(allowedOutboxList.length, true);
                            allowedOutboxList.push(outbox);
                        } else {
                            allowedOutboxList[info.index] = allowedOutboxList[allowedOutboxList.length - 1];
                            allowedOutboxesMap[allowedOutboxList[info.index]].index = info.index;
                            allowedOutboxList.pop();
                            delete allowedOutboxesMap[outbox];
                        }
                    }
                    function setSequencerReportedSubMessageCount(uint256 newMsgCount) external onlyRollupOrOwner {
                        sequencerReportedSubMessageCount = newMsgCount;
                    }
                    function delayedMessageCount() external view override returns (uint256) {
                        return delayedInboxAccs.length;
                    }
                    function sequencerMessageCount() external view returns (uint256) {
                        return sequencerInboxAccs.length;
                    }
                    /// @dev For the classic -> nitro migration. TODO: remove post-migration.
                    function acceptFundsFromOldBridge() external payable {}
                    /// @dev transfer funds provided to pay for crosschain msg
                    function _transferFunds(uint256 amount) internal virtual;
                    function _executeLowLevelCall(
                        address to,
                        uint256 value,
                        bytes memory data
                    ) internal virtual returns (bool success, bytes memory returnData);
                    /// @dev get base fee which is emitted in `MessageDelivered` event and then picked up and
                    /// used in ArbOs to calculate the submission fee for retryable ticket
                    function _baseFeeToReport() internal view virtual returns (uint256);
                    /**
                     * @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[40] private __gap;
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/nitro/blob/master/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.4;
                import "./AbsBridge.sol";
                import "./IERC20Bridge.sol";
                import "../libraries/AddressAliasHelper.sol";
                import {InvalidTokenSet, CallTargetNotAllowed, CallNotAllowed} from "../libraries/Error.sol";
                import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
                import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
                /**
                 * @title Staging ground for incoming and outgoing messages
                 * @notice Unlike the standard Eth bridge, native token bridge escrows the custom ERC20 token which is
                 * used as native currency on L2.
                 * @dev Fees are paid in this token. There are certain restrictions on the native token:
                 *       - The token can't be rebasing or have a transfer fee
                 *       - The token must only be transferrable via a call to the token address itself
                 *       - The token must only be able to set allowance via a call to the token address itself
                 *       - The token must not have a callback on transfer, and more generally a user must not be able to make a transfer to themselves revert
                 */
                contract ERC20Bridge is AbsBridge, IERC20Bridge {
                    using SafeERC20 for IERC20;
                    /// @inheritdoc IERC20Bridge
                    address public nativeToken;
                    /// @inheritdoc IERC20Bridge
                    function initialize(IOwnable rollup_, address nativeToken_) external initializer onlyDelegated {
                        if (nativeToken_ == address(0)) revert InvalidTokenSet(nativeToken_);
                        nativeToken = nativeToken_;
                        _activeOutbox = EMPTY_ACTIVEOUTBOX;
                        rollup = rollup_;
                    }
                    /// @inheritdoc IERC20Bridge
                    function enqueueDelayedMessage(
                        uint8 kind,
                        address sender,
                        bytes32 messageDataHash,
                        uint256 tokenFeeAmount
                    ) external returns (uint256) {
                        return _enqueueDelayedMessage(kind, sender, messageDataHash, tokenFeeAmount);
                    }
                    function _transferFunds(uint256 amount) internal override {
                        // fetch native token from Inbox
                        IERC20(nativeToken).safeTransferFrom(msg.sender, address(this), amount);
                    }
                    function _executeLowLevelCall(
                        address to,
                        uint256 value,
                        bytes memory data
                    ) internal override returns (bool success, bytes memory returnData) {
                        address _nativeToken = nativeToken;
                        // we don't allow outgoing calls to native token contract because it could
                        // result in loss of native tokens which are escrowed by ERC20Bridge
                        if (to == _nativeToken) {
                            revert CallTargetNotAllowed(_nativeToken);
                        }
                        // first release native token
                        IERC20(_nativeToken).safeTransfer(to, value);
                        success = true;
                        // if there's data do additional contract call. Make sure that call is not used to
                        // decrease bridge contract's balance of the native token
                        if (data.length > 0) {
                            uint256 bridgeBalanceBefore = IERC20(_nativeToken).balanceOf(address(this));
                            // solhint-disable-next-line avoid-low-level-calls
                            (success, returnData) = to.call(data);
                            uint256 bridgeBalanceAfter = IERC20(_nativeToken).balanceOf(address(this));
                            if (bridgeBalanceAfter < bridgeBalanceBefore) {
                                revert CallNotAllowed();
                            }
                        }
                    }
                    function _baseFeeToReport() internal pure override returns (uint256) {
                        // ArbOs uses formula 'l1BaseFee * (1400 + 6 * calldataLengthInBytes)' to calculate retryable ticket's
                        // submission fee. When custom ERC20 token is used to pay for fees, submission fee shall be 0. That's
                        // why baseFee is reported as 0 here.
                        return 0;
                    }
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.6.9 <0.9.0;
                import "./IOwnable.sol";
                interface IBridge {
                    event MessageDelivered(
                        uint256 indexed messageIndex,
                        bytes32 indexed beforeInboxAcc,
                        address inbox,
                        uint8 kind,
                        address sender,
                        bytes32 messageDataHash,
                        uint256 baseFeeL1,
                        uint64 timestamp
                    );
                    event BridgeCallTriggered(
                        address indexed outbox,
                        address indexed to,
                        uint256 value,
                        bytes data
                    );
                    event InboxToggle(address indexed inbox, bool enabled);
                    event OutboxToggle(address indexed outbox, bool enabled);
                    event SequencerInboxUpdated(address newSequencerInbox);
                    event RollupUpdated(address rollup);
                    function allowedDelayedInboxList(uint256) external returns (address);
                    function allowedOutboxList(uint256) external returns (address);
                    /// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
                    function delayedInboxAccs(uint256) external view returns (bytes32);
                    /// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
                    function sequencerInboxAccs(uint256) external view returns (bytes32);
                    function rollup() external view returns (IOwnable);
                    function sequencerInbox() external view returns (address);
                    function activeOutbox() external view returns (address);
                    function allowedDelayedInboxes(address inbox) external view returns (bool);
                    function allowedOutboxes(address outbox) external view returns (bool);
                    function sequencerReportedSubMessageCount() external view returns (uint256);
                    function executeCall(
                        address to,
                        uint256 value,
                        bytes calldata data
                    ) external returns (bool success, bytes memory returnData);
                    function delayedMessageCount() external view returns (uint256);
                    function sequencerMessageCount() external view returns (uint256);
                    // ---------- onlySequencerInbox functions ----------
                    function enqueueSequencerMessage(
                        bytes32 dataHash,
                        uint256 afterDelayedMessagesRead,
                        uint256 prevMessageCount,
                        uint256 newMessageCount
                    )
                        external
                        returns (
                            uint256 seqMessageIndex,
                            bytes32 beforeAcc,
                            bytes32 delayedAcc,
                            bytes32 acc
                        );
                    /**
                     * @dev Allows the sequencer inbox to submit a delayed message of the batchPostingReport type
                     *      This is done through a separate function entrypoint instead of allowing the sequencer inbox
                     *      to call `enqueueDelayedMessage` to avoid the gas overhead of an extra SLOAD in either
                     *      every delayed inbox or every sequencer inbox call.
                     */
                    function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
                        external
                        returns (uint256 msgNum);
                    // ---------- onlyRollupOrOwner functions ----------
                    function setSequencerInbox(address _sequencerInbox) external;
                    function setDelayedInbox(address inbox, bool enabled) external;
                    function setOutbox(address inbox, bool enabled) external;
                    function updateRollupAddress(IOwnable _rollup) external;
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/nitro/blob/master/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.6.9 <0.9.0;
                import "./IOwnable.sol";
                import "./IBridge.sol";
                interface IERC20Bridge is IBridge {
                    /**
                     * @dev token that is escrowed in bridge on L1 side and minted on L2 as native currency.
                     * Fees are paid in this token. There are certain restrictions on the native token:
                     *  - The token can't be rebasing or have a transfer fee
                     *  - The token must only be transferrable via a call to the token address itself
                     *  - The token must only be able to set allowance via a call to the token address itself
                     *  - The token must not have a callback on transfer, and more generally a user must not be able to make a transfer to themselves revert
                     */
                    function nativeToken() external view returns (address);
                    /**
                     * @dev Enqueue a message in the delayed inbox accumulator.
                     *      These messages are later sequenced in the SequencerInbox, either
                     *      by the sequencer as part of a normal batch, or by force inclusion.
                     */
                    function enqueueDelayedMessage(
                        uint8 kind,
                        address sender,
                        bytes32 messageDataHash,
                        uint256 tokenFeeAmount
                    ) external returns (uint256);
                    // ---------- initializer ----------
                    function initialize(IOwnable rollup_, address nativeToken_) external;
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                // solhint-disable-next-line compiler-version
                pragma solidity >=0.4.21 <0.9.0;
                interface IOwnable {
                    function owner() external view returns (address);
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.0;
                library Messages {
                    function messageHash(
                        uint8 kind,
                        address sender,
                        uint64 blockNumber,
                        uint64 timestamp,
                        uint256 inboxSeqNum,
                        uint256 baseFeeL1,
                        bytes32 messageDataHash
                    ) internal pure returns (bytes32) {
                        return
                            keccak256(
                                abi.encodePacked(
                                    kind,
                                    sender,
                                    blockNumber,
                                    timestamp,
                                    inboxSeqNum,
                                    baseFeeL1,
                                    messageDataHash
                                )
                            );
                    }
                    function accumulateInboxMessage(bytes32 prevAcc, bytes32 message)
                        internal
                        pure
                        returns (bytes32)
                    {
                        return keccak256(abi.encodePacked(prevAcc, message));
                    }
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.0;
                library AddressAliasHelper {
                    uint160 internal constant OFFSET = uint160(0x1111000000000000000000000000000000001111);
                    /// @notice Utility function that converts the address in the L1 that submitted a tx to
                    /// the inbox to the msg.sender viewed in the L2
                    /// @param l1Address the address in the L1 that triggered the tx to L2
                    /// @return l2Address L2 address as viewed in msg.sender
                    function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
                        unchecked {
                            l2Address = address(uint160(l1Address) + OFFSET);
                        }
                    }
                    /// @notice Utility function that converts the msg.sender viewed in the L2 to the
                    /// address in the L1 that submitted a tx to the inbox
                    /// @param l2Address L2 address as viewed in msg.sender
                    /// @return l1Address the address in the L1 that triggered the tx to L2
                    function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
                        unchecked {
                            l1Address = address(uint160(l2Address) - OFFSET);
                        }
                    }
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.0;
                import {NotOwner} from "./Error.sol";
                /// @dev A stateless contract that allows you to infer if the current call has been delegated or not
                /// Pattern used here is from UUPS implementation by the OpenZeppelin team
                abstract contract DelegateCallAware {
                    address private immutable __self = address(this);
                    /**
                     * @dev Check that the execution is being performed through a delegate call. This allows a function to be
                     * callable on the proxy contract but not on the logic contract.
                     */
                    modifier onlyDelegated() {
                        require(address(this) != __self, "Function must be called through delegatecall");
                        _;
                    }
                    /**
                     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
                     * callable on the implementing contract but not through proxies.
                     */
                    modifier notDelegated() {
                        require(address(this) == __self, "Function must not be called through delegatecall");
                        _;
                    }
                    /// @dev Check that msg.sender is the current EIP 1967 proxy admin
                    modifier onlyProxyOwner() {
                        // Storage slot with the admin of the proxy contract
                        // This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1
                        bytes32 slot = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                        address admin;
                        assembly {
                            admin := sload(slot)
                        }
                        if (msg.sender != admin) revert NotOwner(msg.sender, admin);
                        _;
                    }
                }
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.4;
                /// @dev Init was already called
                error AlreadyInit();
                /// @dev Init was called with param set to zero that must be nonzero
                error HadZeroInit();
                /// @dev Thrown when post upgrade init validation fails
                error BadPostUpgradeInit();
                /// @dev Thrown when non owner tries to access an only-owner function
                /// @param sender The msg.sender who is not the owner
                /// @param owner The owner address
                error NotOwner(address sender, address owner);
                /// @dev Thrown when an address that is not the rollup tries to call an only-rollup function
                /// @param sender The sender who is not the rollup
                /// @param rollup The rollup address authorized to call this function
                error NotRollup(address sender, address rollup);
                /// @dev Thrown when the contract was not called directly from the origin ie msg.sender != tx.origin
                error NotOrigin();
                /// @dev Provided data was too large
                /// @param dataLength The length of the data that is too large
                /// @param maxDataLength The max length the data can be
                error DataTooLarge(uint256 dataLength, uint256 maxDataLength);
                /// @dev The provided is not a contract and was expected to be
                /// @param addr The adddress in question
                error NotContract(address addr);
                /// @dev The merkle proof provided was too long
                /// @param actualLength The length of the merkle proof provided
                /// @param maxProofLength The max length a merkle proof can have
                error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength);
                /// @dev Thrown when an un-authorized address tries to access an admin function
                /// @param sender The un-authorized sender
                /// @param rollup The rollup, which would be authorized
                /// @param owner The rollup's owner, which would be authorized
                error NotRollupOrOwner(address sender, address rollup, address owner);
                // Bridge Errors
                /// @dev Thrown when an un-authorized address tries to access an only-inbox function
                /// @param sender The un-authorized sender
                error NotDelayedInbox(address sender);
                /// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function
                /// @param sender The un-authorized sender
                error NotSequencerInbox(address sender);
                /// @dev Thrown when an un-authorized address tries to access an only-outbox function
                /// @param sender The un-authorized sender
                error NotOutbox(address sender);
                /// @dev the provided outbox address isn't valid
                /// @param outbox address of outbox being set
                error InvalidOutboxSet(address outbox);
                /// @dev The provided token address isn't valid
                /// @param token address of token being set
                error InvalidTokenSet(address token);
                /// @dev Call to this specific address is not allowed
                /// @param target address of the call receiver
                error CallTargetNotAllowed(address target);
                /// @dev Call that changes the balance of ERC20Bridge is not allowed
                error CallNotAllowed();
                // Inbox Errors
                /// @dev The contract is paused, so cannot be paused
                error AlreadyPaused();
                /// @dev The contract is unpaused, so cannot be unpaused
                error AlreadyUnpaused();
                /// @dev The contract is paused
                error Paused();
                /// @dev msg.value sent to the inbox isn't high enough
                error InsufficientValue(uint256 expected, uint256 actual);
                /// @dev submission cost provided isn't enough to create retryable ticket
                error InsufficientSubmissionCost(uint256 expected, uint256 actual);
                /// @dev address not allowed to interact with the given contract
                error NotAllowedOrigin(address origin);
                /// @dev used to convey retryable tx data in eth calls without requiring a tx trace
                /// this follows a pattern similar to EIP-3668 where reverts surface call information
                error RetryableData(
                    address from,
                    address to,
                    uint256 l2CallValue,
                    uint256 deposit,
                    uint256 maxSubmissionCost,
                    address excessFeeRefundAddress,
                    address callValueRefundAddress,
                    uint256 gasLimit,
                    uint256 maxFeePerGas,
                    bytes data
                );
                /// @dev Thrown when a L1 chainId fork is detected
                error L1Forked();
                /// @dev Thrown when a L1 chainId fork is not detected
                error NotForked();
                /// @dev The provided gasLimit is larger than uint64
                error GasLimitTooLarge();
                // Outbox Errors
                /// @dev The provided proof was too long
                /// @param proofLength The length of the too-long proof
                error ProofTooLong(uint256 proofLength);
                /// @dev The output index was greater than the maximum
                /// @param index The output index
                /// @param maxIndex The max the index could be
                error PathNotMinimal(uint256 index, uint256 maxIndex);
                /// @dev The calculated root does not exist
                /// @param root The calculated root
                error UnknownRoot(bytes32 root);
                /// @dev The record has already been spent
                /// @param index The index of the spent record
                error AlreadySpent(uint256 index);
                /// @dev A call to the bridge failed with no return data
                error BridgeCallFailed();
                // Sequencer Inbox Errors
                /// @dev Thrown when someone attempts to read fewer messages than have already been read
                error DelayedBackwards();
                /// @dev Thrown when someone attempts to read more messages than exist
                error DelayedTooFar();
                /// @dev Force include can only read messages more blocks old than the delay period
                error ForceIncludeBlockTooSoon();
                /// @dev Force include can only read messages more seconds old than the delay period
                error ForceIncludeTimeTooSoon();
                /// @dev The message provided did not match the hash in the delayed inbox
                error IncorrectMessagePreimage();
                /// @dev This can only be called by the batch poster
                error NotBatchPoster();
                /// @dev The sequence number provided to this message was inconsistent with the number of batches already included
                error BadSequencerNumber(uint256 stored, uint256 received);
                /// @dev The sequence message number provided to this message was inconsistent with the previous one
                error BadSequencerMessageNumber(uint256 stored, uint256 received);
                /// @dev The batch data has the inbox authenticated bit set, but the batch data was not authenticated by the inbox
                error DataNotAuthenticated();
                /// @dev Tried to create an already valid Data Availability Service keyset
                error AlreadyValidDASKeyset(bytes32);
                /// @dev Tried to use or invalidate an already invalid Data Availability Service keyset
                error NoSuchKeyset(bytes32);
                /// @dev Thrown when rollup is not updated with updateRollupAddress
                error RollupNotChanged();
                // Copyright 2021-2022, Offchain Labs, Inc.
                // For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
                // SPDX-License-Identifier: BUSL-1.1
                pragma solidity ^0.8.4;
                uint8 constant L2_MSG = 3;
                uint8 constant L1MessageType_L2FundedByL1 = 7;
                uint8 constant L1MessageType_submitRetryableTx = 9;
                uint8 constant L1MessageType_ethDeposit = 12;
                uint8 constant L1MessageType_batchPostingReport = 13;
                uint8 constant L2MessageType_unsignedEOATx = 0;
                uint8 constant L2MessageType_unsignedContractTx = 1;
                uint8 constant ROLLUP_PROTOCOL_EVENT_TYPE = 8;
                uint8 constant INITIALIZATION_MSG_TYPE = 11;