ETH Price: $2,001.87 (-3.51%)

Transaction Decoder

Block:
19042210 at Jan-19-2024 04:49:23 PM +UTC
Transaction Fee:
0.015875903009787359 ETH $31.78
Gas Used:
233,279 Gas / 68.055431521 Gwei

Emitted Events:

225 TransparentUpgradeableProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000b0a7dbfa001e7f710c01924f5fc56cacf5ce9a28, 0x00000000000000000000000088011e1e335e4dde0eb0dc37d23c57bdd00c543e, 0x0000000000000000000000000000000000000000000000000000000000001bc5 )
226 TransparentUpgradeableProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000b0a7dbfa001e7f710c01924f5fc56cacf5ce9a28, 0x00000000000000000000000088011e1e335e4dde0eb0dc37d23c57bdd00c543e, 0x0000000000000000000000000000000000000000000000000000000000001a27 )
227 0xb2ecfe4e4d61f8790bbb9de2d1259b9e2410cea5.0x0fcf17fac114131b10f37b183c6a60f905911e52802caeeb3e6ea210398b81ab( 0x0fcf17fac114131b10f37b183c6a60f905911e52802caeeb3e6ea210398b81ab, b8c25405501008617a61a1c7d1e2218c3f0327f40d83f031e85334c9718eceed, 0000000000000000001bc50088011e1e335e4dde0eb0dc37d23c57bdd00c543e, 0100000000470de4df820000b10b88218e288cda2218d8b4cc81899ee5af4600, 0000000000000000000001f4ea9b1ed511632e48ddd3e5a231cd2f5f3a3a4a9b )
228 0xb2ecfe4e4d61f8790bbb9de2d1259b9e2410cea5.0x0fcf17fac114131b10f37b183c6a60f905911e52802caeeb3e6ea210398b81ab( 0x0fcf17fac114131b10f37b183c6a60f905911e52802caeeb3e6ea210398b81ab, b8c25405501008617a61a1c7d1e2218c3f0327f40d83f031e85334c9718eceed, 0000000000000000001a270088011e1e335e4dde0eb0dc37d23c57bdd00c543e, 0100000000470de4df820000b10b88218e288cda2218d8b4cc81899ee5af4600, 0000000000000000000001f4ea9b1ed511632e48ddd3e5a231cd2f5f3a3a4a9b )
229 ERC1967Proxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x00000000000000000000000088011e1e335e4dde0eb0dc37d23c57bdd00c543e, 0x000000000000000000000000b2ecfe4e4d61f8790bbb9de2d1259b9e2410cea5, 000000000000000000000000000000000000000000000000008e1bc9bf040000 )
230 ERC1967Proxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000b2ecfe4e4d61f8790bbb9de2d1259b9e2410cea5, 0x000000000000000000000000b0a7dbfa001e7f710c01924f5fc56cacf5ce9a28, 000000000000000000000000000000000000000000000000008700cc75770000 )
231 ERC1967Proxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000b2ecfe4e4d61f8790bbb9de2d1259b9e2410cea5, 0x000000000000000000000000ea9b1ed511632e48ddd3e5a231cd2f5f3a3a4a9b, 00000000000000000000000000000000000000000000000000071afd498d0000 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...d351887Ac
(beaverbuild)
13.454685361039557325 Eth13.454708688939557325 Eth0.0000233279
0xB0a7dbfa...Cf5ce9A28
0.025963773163056305 Eth
Nonce: 2342
0.010087870153268946 Eth
Nonce: 2343
0.015875903009787359
0xB10B8821...Ee5Af4600
0xb2ecfE4E...e2410CEA5
(Blur.io: Marketplace 3)

Execution Trace

Blur.io: Marketplace 3.7034d120( )
  • 0x5fa60726e62c50af45ff2f6280c468da438a7837.7034d120( )
    • Null: 0x000...001.43f0ee67( )
    • Null: 0x000...001.3a2c04ad( )
    • Delegate.transfer( taker=0xB0a7dbfa001e7F710c01924F5fc56caCf5ce9A28, orderType=1, transfers=, length=2 ) => ( successful=[true, true] )
      • TransparentUpgradeableProxy.42842e0e( )
        • UtilityWenUpgradeable.safeTransferFrom( from=0xB0a7dbfa001e7F710c01924F5fc56caCf5ce9A28, to=0x88011e1E335e4DDE0eB0Dc37d23c57BDd00c543e, tokenId=7109 )
          • OperatorFilterRegistry.isOperatorAllowed( registrant=0xB10B88218E288CdA2218d8B4cc81899Ee5Af4600, operator=0x2f18F339620a63e43f0839Eeb18D7de1e1Be4DfB ) => ( True )
          • OperatorFilterRegistry.isOperatorAllowed( registrant=0xB10B88218E288CdA2218d8B4cc81899Ee5Af4600, operator=0x2f18F339620a63e43f0839Eeb18D7de1e1Be4DfB ) => ( True )
          • OperatorFilterRegistry.isOperatorAllowed( registrant=0xB10B88218E288CdA2218d8B4cc81899Ee5Af4600, operator=0x2f18F339620a63e43f0839Eeb18D7de1e1Be4DfB ) => ( True )
          • TransparentUpgradeableProxy.42842e0e( )
            • UtilityWenUpgradeable.safeTransferFrom( from=0xB0a7dbfa001e7F710c01924F5fc56caCf5ce9A28, to=0x88011e1E335e4DDE0eB0Dc37d23c57BDd00c543e, tokenId=6695 )
              • OperatorFilterRegistry.isOperatorAllowed( registrant=0xB10B88218E288CdA2218d8B4cc81899Ee5Af4600, operator=0x2f18F339620a63e43f0839Eeb18D7de1e1Be4DfB ) => ( True )
              • OperatorFilterRegistry.isOperatorAllowed( registrant=0xB10B88218E288CdA2218d8B4cc81899Ee5Af4600, operator=0x2f18F339620a63e43f0839Eeb18D7de1e1Be4DfB ) => ( True )
              • OperatorFilterRegistry.isOperatorAllowed( registrant=0xB10B88218E288CdA2218d8B4cc81899Ee5Af4600, operator=0x2f18F339620a63e43f0839Eeb18D7de1e1Be4DfB ) => ( True )
              • ERC1967Proxy.23b872dd( )
                • BlurPool.transferFrom( from=0x88011e1E335e4DDE0eB0Dc37d23c57BDd00c543e, to=0xb2ecfE4E4D61f8790bbb9DE2D1259B9e2410CEA5, amount=40000000000000000 ) => ( True )
                • ERC1967Proxy.23b872dd( )
                  • BlurPool.transferFrom( from=0xb2ecfE4E4D61f8790bbb9DE2D1259B9e2410CEA5, to=0xB0a7dbfa001e7F710c01924F5fc56caCf5ce9A28, amount=38000000000000000 ) => ( True )
                  • ERC1967Proxy.23b872dd( )
                    • BlurPool.transferFrom( from=0xb2ecfE4E4D61f8790bbb9DE2D1259B9e2410CEA5, to=0xeA9B1Ed511632e48dDD3E5A231cd2f5F3A3a4a9b, amount=2000000000000000 ) => ( True )
                      File 1 of 6: TransparentUpgradeableProxy
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
                      import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
                      import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
                      // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
                      contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
                          constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
                      }
                      // SPDX-License-Identifier: MIT
                      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
                      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
                      pragma solidity ^0.8.0;
                      import "./TransparentUpgradeableProxy.sol";
                      import "../../access/Ownable.sol";
                      /**
                       * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
                       * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
                       */
                      contract ProxyAdmin is Ownable {
                          /**
                           * @dev Returns the current implementation of `proxy`.
                           *
                           * Requirements:
                           *
                           * - This contract must be the admin of `proxy`.
                           */
                          function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                              // We need to manually run the static call since the getter cannot be flagged as view
                              // bytes4(keccak256("implementation()")) == 0x5c60da1b
                              (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                              require(success);
                              return abi.decode(returndata, (address));
                          }
                          /**
                           * @dev Returns the current admin of `proxy`.
                           *
                           * Requirements:
                           *
                           * - This contract must be the admin of `proxy`.
                           */
                          function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                              // We need to manually run the static call since the getter cannot be flagged as view
                              // bytes4(keccak256("admin()")) == 0xf851a440
                              (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                              require(success);
                              return abi.decode(returndata, (address));
                          }
                          /**
                           * @dev Changes the admin of `proxy` to `newAdmin`.
                           *
                           * Requirements:
                           *
                           * - This contract must be the current admin of `proxy`.
                           */
                          function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                              proxy.changeAdmin(newAdmin);
                          }
                          /**
                           * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
                           *
                           * Requirements:
                           *
                           * - This contract must be the admin of `proxy`.
                           */
                          function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                              proxy.upgradeTo(implementation);
                          }
                          /**
                           * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
                           * {TransparentUpgradeableProxy-upgradeToAndCall}.
                           *
                           * Requirements:
                           *
                           * - This contract must be the admin of `proxy`.
                           */
                          function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                              proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      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 internall call site, it will return directly to the external caller.
                           */
                          function _delegate(address implementation) internal virtual {
                              // solhint-disable-next-line no-inline-assembly
                              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
                      pragma solidity ^0.8.2;
                      import "../beacon/IBeacon.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 {
                              _setImplementation(newImplementation);
                              emit Upgraded(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 _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                              address oldImplementation = _getImplementation();
                              // Initial upgrade and setup call
                              _setImplementation(newImplementation);
                              if (data.length > 0 || forceCall) {
                                  Address.functionDelegateCall(newImplementation, data);
                              }
                              // Perform rollback test if not already in progress
                              StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                              if (!rollbackTesting.value) {
                                  // Trigger rollback using upgradeTo from the new implementation
                                  rollbackTesting.value = true;
                                  Address.functionDelegateCall(
                                      newImplementation,
                                      abi.encodeWithSignature(
                                          "upgradeTo(address)",
                                          oldImplementation
                                      )
                                  );
                                  rollbackTesting.value = false;
                                  // Check rollback was effective
                                  require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                                  // Finally reset to the new implementation and log the upgrade
                                  _setImplementation(newImplementation);
                                  emit Upgraded(newImplementation);
                              }
                          }
                          /**
                           * @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);
                              }
                          }
                          /**
                           * @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;
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      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
                      pragma solidity ^0.8.0;
                      /**
                       * @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
                           * ====
                           */
                          function isContract(address account) internal view returns (bool) {
                              // This method relies on extcodesize, which returns 0 for contracts in
                              // construction, since the code is only stored at the end of the
                              // constructor execution.
                              uint256 size;
                              // solhint-disable-next-line no-inline-assembly
                              assembly { size := extcodesize(account) }
                              return size > 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");
                              // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                              (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");
                              // solhint-disable-next-line avoid-low-level-calls
                              (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");
                              // solhint-disable-next-line avoid-low-level-calls
                              (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");
                              // solhint-disable-next-line avoid-low-level-calls
                              (bool success, bytes memory returndata) = target.delegatecall(data);
                              return _verifyCallResult(success, returndata, errorMessage);
                          }
                          function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private 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
                                      // solhint-disable-next-line no-inline-assembly
                                      assembly {
                                          let returndata_size := mload(returndata)
                                          revert(add(32, returndata), returndata_size)
                                      }
                                  } else {
                                      revert(errorMessage);
                                  }
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      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
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      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 () {
                              address msgSender = _msgSender();
                              _owner = msgSender;
                              emit OwnershipTransferred(address(0), msgSender);
                          }
                          /**
                           * @dev Returns the address of the current owner.
                           */
                          function owner() public view virtual returns (address) {
                              return _owner;
                          }
                          /**
                           * @dev Throws if called by any account other than the owner.
                           */
                          modifier onlyOwner() {
                              require(owner() == _msgSender(), "Ownable: caller is not the owner");
                              _;
                          }
                          /**
                           * @dev Leaves the contract without owner. It will not be possible to call
                           * `onlyOwner` functions anymore. Can only be called by the current owner.
                           *
                           * NOTE: Renouncing ownership will leave the contract without an owner,
                           * thereby removing any functionality that is only available to the owner.
                           */
                          function renounceOwnership() public virtual onlyOwner {
                              emit OwnershipTransferred(_owner, address(0));
                              _owner = address(0);
                          }
                          /**
                           * @dev Transfers ownership of the contract to a new account (`newOwner`).
                           * Can only be called by the current owner.
                           */
                          function transferOwnership(address newOwner) public virtual onlyOwner {
                              require(newOwner != address(0), "Ownable: new owner is the zero address");
                              emit OwnershipTransferred(_owner, newOwner);
                              _owner = newOwner;
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.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) {
                              this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                              return msg.data;
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      import "../ERC1967/ERC1967Upgrade.sol";
                      /**
                       * @dev Base contract for building openzeppelin-upgrades compatible implementations for the {ERC1967Proxy}. It includes
                       * publicly available upgrade functions that are called by the plugin and by the secure upgrade mechanism to verify
                       * continuation of the upgradability.
                       *
                       * The {_authorizeUpgrade} function MUST be overridden to include access restriction to the upgrade mechanism.
                       *
                       * _Available since v4.1._
                       */
                      abstract contract UUPSUpgradeable is ERC1967Upgrade {
                          function upgradeTo(address newImplementation) external virtual {
                              _authorizeUpgrade(newImplementation);
                              _upgradeToAndCallSecure(newImplementation, bytes(""), false);
                          }
                          function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual {
                              _authorizeUpgrade(newImplementation);
                              _upgradeToAndCallSecure(newImplementation, data, true);
                          }
                          function _authorizeUpgrade(address newImplementation) internal virtual;
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.2;
                      import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
                      abstract contract Proxiable is UUPSUpgradeable {
                          function _authorizeUpgrade(address newImplementation) internal override {
                              _beforeUpgrade(newImplementation);
                          }
                          function _beforeUpgrade(address newImplementation) internal virtual;
                      }
                      contract ChildOfProxiable is Proxiable {
                          function _beforeUpgrade(address newImplementation) internal virtual override {}
                      }
                      

                      File 2 of 6: ERC1967Proxy
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)
                      pragma solidity 0.8.17;
                      // OpenZeppelin Contracts v4.4.1 (proxy/Proxy.sol)
                      /**
                       * @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 internall 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 {}
                      }
                      // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Upgrade.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 _upgradeToAndCallSecure(
                              address newImplementation,
                              bytes memory data,
                              bool forceCall
                          ) internal {
                              address oldImplementation = _getImplementation();
                              // Initial upgrade and setup call
                              _setImplementation(newImplementation);
                              if (data.length > 0 || forceCall) {
                                  Address.functionDelegateCall(newImplementation, data);
                              }
                              // Perform rollback test if not already in progress
                              StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                              if (!rollbackTesting.value) {
                                  // Trigger rollback using upgradeTo from the new implementation
                                  rollbackTesting.value = true;
                                  Address.functionDelegateCall(
                                      newImplementation,
                                      abi.encodeWithSignature("upgradeTo(address)", oldImplementation)
                                  );
                                  rollbackTesting.value = false;
                                  // Check rollback was effective
                                  require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                                  // Finally reset to the new implementation and log the upgrade
                                  _upgradeTo(newImplementation);
                              }
                          }
                          /**
                           * @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);
                              }
                          }
                      }
                      /**
                       * @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();
                          }
                      }
                      // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
                      /**
                       * @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);
                      }
                      // OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @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
                           * ====
                           */
                          function isContract(address account) internal view returns (bool) {
                              // This method relies on extcodesize, which returns 0 for contracts in
                              // construction, since the code is only stored at the end of the
                              // constructor execution.
                              uint256 size;
                              assembly {
                                  size := extcodesize(account)
                              }
                              return size > 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);
                                  }
                              }
                          }
                      }
                      // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)
                      /**
                       * @dev Library for reading and writing primitive types to specific storage slots.
                       *
                       * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                       * This library helps with reading and writing to such slots without the need for inline assembly.
                       *
                       * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                       *
                       * Example usage to set ERC1967 implementation slot:
                       * ```
                       * contract ERC1967 {
                       *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                       *
                       *     function _getImplementation() internal view returns (address) {
                       *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                       *     }
                       *
                       *     function _setImplementation(address newImplementation) internal {
                       *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                       *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                       *     }
                       * }
                       * ```
                       *
                       * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
                       */
                      library StorageSlot {
                          struct AddressSlot {
                              address value;
                          }
                          struct BooleanSlot {
                              bool value;
                          }
                          struct Bytes32Slot {
                              bytes32 value;
                          }
                          struct Uint256Slot {
                              uint256 value;
                          }
                          /**
                           * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                           */
                          function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                           */
                          function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                           */
                          function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                           */
                          function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                              assembly {
                                  r.slot := slot
                              }
                          }
                      }

                      File 3 of 6: Delegate
                      // SPDX-License-Identifier: MIT
                      pragma solidity 0.8.17;
                      import { ERC721 } from "lib/solmate/src/tokens/ERC721.sol";
                      import { ERC1155 } from "lib/solmate/src/tokens/ERC1155.sol";
                      import { ERC20 } from "lib/solmate/src/tokens/ERC20.sol";
                      import "./lib/Constants.sol";
                      import { AssetType, OrderType, Transfer } from "./lib/Structs.sol";
                      contract Delegate {
                          error Unauthorized();
                          error InvalidLength();
                          address private immutable _EXCHANGE;
                          constructor(address exchange) {
                              _EXCHANGE = exchange;
                          }
                          modifier onlyApproved() {
                              if (msg.sender != _EXCHANGE) {
                                  revert Unauthorized();
                              }
                              _;
                          }
                          function transfer(
                              address taker,
                              OrderType orderType,
                              Transfer[] calldata transfers,
                              uint256 length
                          ) external onlyApproved returns (bool[] memory successful) {
                              if (transfers.length < length) {
                                  revert InvalidLength();
                              }
                              successful = new bool[](length);
                              for (uint256 i; i < length; ) {
                                  assembly {
                                      let calldataPointer := mload(0x40)
                                      let transfersPointer := add(transfers.offset, mul(Transfer_size, i))
                                      let assetType := calldataload(add(transfersPointer, Transfer_assetType_offset))
                                      switch assetType
                                      case 0 {
                                          // AssetType_ERC721
                                          mstore(calldataPointer, ERC721_safeTransferFrom_selector)
                                          switch orderType
                                          case 0 {
                                              // OrderType_ASK; taker is recipient
                                              mstore(add(calldataPointer, ERC721_safeTransferFrom_to_offset), taker)
                                              mstore(
                                                  add(calldataPointer, ERC721_safeTransferFrom_from_offset),
                                                  calldataload(add(transfersPointer, Transfer_trader_offset))
                                              )
                                          }
                                          case 1 {
                                              // OrderType_BID; taker is sender
                                              mstore(add(calldataPointer, ERC721_safeTransferFrom_from_offset), taker)
                                              mstore(
                                                  add(calldataPointer, ERC721_safeTransferFrom_to_offset),
                                                  calldataload(add(transfersPointer, Transfer_trader_offset))
                                              )
                                          }
                                          default {
                                              revert(0, 0)
                                          }
                                          mstore(
                                              add(calldataPointer, ERC721_safeTransferFrom_id_offset),
                                              calldataload(add(transfersPointer, Transfer_id_offset))
                                          )
                                          let collection := calldataload(
                                              add(transfersPointer, Transfer_collection_offset)
                                          )
                                          let success := call(
                                              gas(),
                                              collection,
                                              0,
                                              calldataPointer,
                                              ERC721_safeTransferFrom_size,
                                              0,
                                              0
                                          )
                                          mstore(add(add(successful, 0x20), mul(0x20, i)), success)
                                      }
                                      case 1 {
                                          // AssetType_ERC1155
                                          mstore(calldataPointer, ERC1155_safeTransferFrom_selector)
                                          switch orderType
                                          case 0 {
                                              // OrderType_ASK; taker is recipient
                                              mstore(
                                                  add(calldataPointer, ERC1155_safeTransferFrom_from_offset),
                                                  calldataload(
                                                      add(
                                                          transfersPointer,
                                                          Transfer_trader_offset
                                                      )
                                                  )
                                              )
                                              mstore(add(calldataPointer, ERC1155_safeTransferFrom_to_offset), taker)
                                          }
                                          case 1 {
                                              // OrderType_BID; taker is sender
                                              mstore(
                                                  add(calldataPointer, ERC1155_safeTransferFrom_to_offset),
                                                  calldataload(
                                                      add(
                                                          transfersPointer,
                                                          Transfer_trader_offset
                                                      )
                                                  )
                                              )
                                              mstore(add(calldataPointer, ERC1155_safeTransferFrom_from_offset), taker)
                                          }
                                          default {
                                              revert(0, 0)
                                          }
                                          mstore(add(calldataPointer, ERC1155_safeTransferFrom_data_pointer_offset), 0xa0)
                                          mstore(add(calldataPointer, ERC1155_safeTransferFrom_data_offset), 0)
                                          mstore(
                                              add(calldataPointer, ERC1155_safeTransferFrom_id_offset),
                                              calldataload(
                                                  add(transfersPointer, Transfer_id_offset)
                                              )
                                          )
                                          mstore(
                                              add(calldataPointer, ERC1155_safeTransferFrom_amount_offset),
                                              calldataload(
                                                  add(
                                                      transfersPointer,
                                                      Transfer_amount_offset
                                                  )
                                              )
                                          )
                                          let collection := calldataload(
                                              add(
                                                  transfersPointer,
                                                  Transfer_collection_offset
                                              )
                                          )
                                          let success := call(
                                              gas(),
                                              collection,
                                              0,
                                              calldataPointer,
                                              ERC1155_safeTransferFrom_size,
                                              0,
                                              0
                                          )
                                          mstore(add(add(successful, 0x20), mul(0x20, i)), success)
                                      }
                                      default {
                                          revert(0, 0)
                                      }
                                  }
                                  unchecked {
                                      ++i;
                                  }
                              }
                          }
                      }
                      // SPDX-License-Identifier: AGPL-3.0-only
                      pragma solidity >=0.8.0;
                      /// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
                      /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
                      abstract contract ERC721 {
                          /*//////////////////////////////////////////////////////////////
                                                       EVENTS
                          //////////////////////////////////////////////////////////////*/
                          event Transfer(address indexed from, address indexed to, uint256 indexed id);
                          event Approval(address indexed owner, address indexed spender, uint256 indexed id);
                          event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
                          /*//////////////////////////////////////////////////////////////
                                               METADATA STORAGE/LOGIC
                          //////////////////////////////////////////////////////////////*/
                          string public name;
                          string public symbol;
                          function tokenURI(uint256 id) public view virtual returns (string memory);
                          /*//////////////////////////////////////////////////////////////
                                            ERC721 BALANCE/OWNER STORAGE
                          //////////////////////////////////////////////////////////////*/
                          mapping(uint256 => address) internal _ownerOf;
                          mapping(address => uint256) internal _balanceOf;
                          function ownerOf(uint256 id) public view virtual returns (address owner) {
                              require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
                          }
                          function balanceOf(address owner) public view virtual returns (uint256) {
                              require(owner != address(0), "ZERO_ADDRESS");
                              return _balanceOf[owner];
                          }
                          /*//////////////////////////////////////////////////////////////
                                               ERC721 APPROVAL STORAGE
                          //////////////////////////////////////////////////////////////*/
                          mapping(uint256 => address) public getApproved;
                          mapping(address => mapping(address => bool)) public isApprovedForAll;
                          /*//////////////////////////////////////////////////////////////
                                                     CONSTRUCTOR
                          //////////////////////////////////////////////////////////////*/
                          constructor(string memory _name, string memory _symbol) {
                              name = _name;
                              symbol = _symbol;
                          }
                          /*//////////////////////////////////////////////////////////////
                                                    ERC721 LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function approve(address spender, uint256 id) public virtual {
                              address owner = _ownerOf[id];
                              require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");
                              getApproved[id] = spender;
                              emit Approval(owner, spender, id);
                          }
                          function setApprovalForAll(address operator, bool approved) public virtual {
                              isApprovedForAll[msg.sender][operator] = approved;
                              emit ApprovalForAll(msg.sender, operator, approved);
                          }
                          function transferFrom(
                              address from,
                              address to,
                              uint256 id
                          ) public virtual {
                              require(from == _ownerOf[id], "WRONG_FROM");
                              require(to != address(0), "INVALID_RECIPIENT");
                              require(
                                  msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
                                  "NOT_AUTHORIZED"
                              );
                              // Underflow of the sender's balance is impossible because we check for
                              // ownership above and the recipient's balance can't realistically overflow.
                              unchecked {
                                  _balanceOf[from]--;
                                  _balanceOf[to]++;
                              }
                              _ownerOf[id] = to;
                              delete getApproved[id];
                              emit Transfer(from, to, id);
                          }
                          function safeTransferFrom(
                              address from,
                              address to,
                              uint256 id
                          ) public virtual {
                              transferFrom(from, to, id);
                              require(
                                  to.code.length == 0 ||
                                      ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                                      ERC721TokenReceiver.onERC721Received.selector,
                                  "UNSAFE_RECIPIENT"
                              );
                          }
                          function safeTransferFrom(
                              address from,
                              address to,
                              uint256 id,
                              bytes calldata data
                          ) public virtual {
                              transferFrom(from, to, id);
                              require(
                                  to.code.length == 0 ||
                                      ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                                      ERC721TokenReceiver.onERC721Received.selector,
                                  "UNSAFE_RECIPIENT"
                              );
                          }
                          /*//////////////////////////////////////////////////////////////
                                                    ERC165 LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
                              return
                                  interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
                                  interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
                                  interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
                          }
                          /*//////////////////////////////////////////////////////////////
                                              INTERNAL MINT/BURN LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function _mint(address to, uint256 id) internal virtual {
                              require(to != address(0), "INVALID_RECIPIENT");
                              require(_ownerOf[id] == address(0), "ALREADY_MINTED");
                              // Counter overflow is incredibly unrealistic.
                              unchecked {
                                  _balanceOf[to]++;
                              }
                              _ownerOf[id] = to;
                              emit Transfer(address(0), to, id);
                          }
                          function _burn(uint256 id) internal virtual {
                              address owner = _ownerOf[id];
                              require(owner != address(0), "NOT_MINTED");
                              // Ownership check above ensures no underflow.
                              unchecked {
                                  _balanceOf[owner]--;
                              }
                              delete _ownerOf[id];
                              delete getApproved[id];
                              emit Transfer(owner, address(0), id);
                          }
                          /*//////////////////////////////////////////////////////////////
                                              INTERNAL SAFE MINT LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function _safeMint(address to, uint256 id) internal virtual {
                              _mint(to, id);
                              require(
                                  to.code.length == 0 ||
                                      ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                                      ERC721TokenReceiver.onERC721Received.selector,
                                  "UNSAFE_RECIPIENT"
                              );
                          }
                          function _safeMint(
                              address to,
                              uint256 id,
                              bytes memory data
                          ) internal virtual {
                              _mint(to, id);
                              require(
                                  to.code.length == 0 ||
                                      ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                                      ERC721TokenReceiver.onERC721Received.selector,
                                  "UNSAFE_RECIPIENT"
                              );
                          }
                      }
                      /// @notice A generic interface for a contract which properly accepts ERC721 tokens.
                      /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
                      abstract contract ERC721TokenReceiver {
                          function onERC721Received(
                              address,
                              address,
                              uint256,
                              bytes calldata
                          ) external virtual returns (bytes4) {
                              return ERC721TokenReceiver.onERC721Received.selector;
                          }
                      }
                      // SPDX-License-Identifier: AGPL-3.0-only
                      pragma solidity >=0.8.0;
                      /// @notice Minimalist and gas efficient standard ERC1155 implementation.
                      /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
                      abstract contract ERC1155 {
                          /*//////////////////////////////////////////////////////////////
                                                       EVENTS
                          //////////////////////////////////////////////////////////////*/
                          event TransferSingle(
                              address indexed operator,
                              address indexed from,
                              address indexed to,
                              uint256 id,
                              uint256 amount
                          );
                          event TransferBatch(
                              address indexed operator,
                              address indexed from,
                              address indexed to,
                              uint256[] ids,
                              uint256[] amounts
                          );
                          event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
                          event URI(string value, uint256 indexed id);
                          /*//////////////////////////////////////////////////////////////
                                                   ERC1155 STORAGE
                          //////////////////////////////////////////////////////////////*/
                          mapping(address => mapping(uint256 => uint256)) public balanceOf;
                          mapping(address => mapping(address => bool)) public isApprovedForAll;
                          /*//////////////////////////////////////////////////////////////
                                                   METADATA LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function uri(uint256 id) public view virtual returns (string memory);
                          /*//////////////////////////////////////////////////////////////
                                                    ERC1155 LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function setApprovalForAll(address operator, bool approved) public virtual {
                              isApprovedForAll[msg.sender][operator] = approved;
                              emit ApprovalForAll(msg.sender, operator, approved);
                          }
                          function safeTransferFrom(
                              address from,
                              address to,
                              uint256 id,
                              uint256 amount,
                              bytes calldata data
                          ) public virtual {
                              require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");
                              balanceOf[from][id] -= amount;
                              balanceOf[to][id] += amount;
                              emit TransferSingle(msg.sender, from, to, id, amount);
                              require(
                                  to.code.length == 0
                                      ? to != address(0)
                                      : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) ==
                                          ERC1155TokenReceiver.onERC1155Received.selector,
                                  "UNSAFE_RECIPIENT"
                              );
                          }
                          function safeBatchTransferFrom(
                              address from,
                              address to,
                              uint256[] calldata ids,
                              uint256[] calldata amounts,
                              bytes calldata data
                          ) public virtual {
                              require(ids.length == amounts.length, "LENGTH_MISMATCH");
                              require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");
                              // Storing these outside the loop saves ~15 gas per iteration.
                              uint256 id;
                              uint256 amount;
                              for (uint256 i = 0; i < ids.length; ) {
                                  id = ids[i];
                                  amount = amounts[i];
                                  balanceOf[from][id] -= amount;
                                  balanceOf[to][id] += amount;
                                  // An array can't have a total length
                                  // larger than the max uint256 value.
                                  unchecked {
                                      ++i;
                                  }
                              }
                              emit TransferBatch(msg.sender, from, to, ids, amounts);
                              require(
                                  to.code.length == 0
                                      ? to != address(0)
                                      : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) ==
                                          ERC1155TokenReceiver.onERC1155BatchReceived.selector,
                                  "UNSAFE_RECIPIENT"
                              );
                          }
                          function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
                              public
                              view
                              virtual
                              returns (uint256[] memory balances)
                          {
                              require(owners.length == ids.length, "LENGTH_MISMATCH");
                              balances = new uint256[](owners.length);
                              // Unchecked because the only math done is incrementing
                              // the array index counter which cannot possibly overflow.
                              unchecked {
                                  for (uint256 i = 0; i < owners.length; ++i) {
                                      balances[i] = balanceOf[owners[i]][ids[i]];
                                  }
                              }
                          }
                          /*//////////////////////////////////////////////////////////////
                                                    ERC165 LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
                              return
                                  interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
                                  interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
                                  interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
                          }
                          /*//////////////////////////////////////////////////////////////
                                              INTERNAL MINT/BURN LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function _mint(
                              address to,
                              uint256 id,
                              uint256 amount,
                              bytes memory data
                          ) internal virtual {
                              balanceOf[to][id] += amount;
                              emit TransferSingle(msg.sender, address(0), to, id, amount);
                              require(
                                  to.code.length == 0
                                      ? to != address(0)
                                      : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) ==
                                          ERC1155TokenReceiver.onERC1155Received.selector,
                                  "UNSAFE_RECIPIENT"
                              );
                          }
                          function _batchMint(
                              address to,
                              uint256[] memory ids,
                              uint256[] memory amounts,
                              bytes memory data
                          ) internal virtual {
                              uint256 idsLength = ids.length; // Saves MLOADs.
                              require(idsLength == amounts.length, "LENGTH_MISMATCH");
                              for (uint256 i = 0; i < idsLength; ) {
                                  balanceOf[to][ids[i]] += amounts[i];
                                  // An array can't have a total length
                                  // larger than the max uint256 value.
                                  unchecked {
                                      ++i;
                                  }
                              }
                              emit TransferBatch(msg.sender, address(0), to, ids, amounts);
                              require(
                                  to.code.length == 0
                                      ? to != address(0)
                                      : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) ==
                                          ERC1155TokenReceiver.onERC1155BatchReceived.selector,
                                  "UNSAFE_RECIPIENT"
                              );
                          }
                          function _batchBurn(
                              address from,
                              uint256[] memory ids,
                              uint256[] memory amounts
                          ) internal virtual {
                              uint256 idsLength = ids.length; // Saves MLOADs.
                              require(idsLength == amounts.length, "LENGTH_MISMATCH");
                              for (uint256 i = 0; i < idsLength; ) {
                                  balanceOf[from][ids[i]] -= amounts[i];
                                  // An array can't have a total length
                                  // larger than the max uint256 value.
                                  unchecked {
                                      ++i;
                                  }
                              }
                              emit TransferBatch(msg.sender, from, address(0), ids, amounts);
                          }
                          function _burn(
                              address from,
                              uint256 id,
                              uint256 amount
                          ) internal virtual {
                              balanceOf[from][id] -= amount;
                              emit TransferSingle(msg.sender, from, address(0), id, amount);
                          }
                      }
                      /// @notice A generic interface for a contract which properly accepts ERC1155 tokens.
                      /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
                      abstract contract ERC1155TokenReceiver {
                          function onERC1155Received(
                              address,
                              address,
                              uint256,
                              uint256,
                              bytes calldata
                          ) external virtual returns (bytes4) {
                              return ERC1155TokenReceiver.onERC1155Received.selector;
                          }
                          function onERC1155BatchReceived(
                              address,
                              address,
                              uint256[] calldata,
                              uint256[] calldata,
                              bytes calldata
                          ) external virtual returns (bytes4) {
                              return ERC1155TokenReceiver.onERC1155BatchReceived.selector;
                          }
                      }
                      // SPDX-License-Identifier: AGPL-3.0-only
                      pragma solidity >=0.8.0;
                      /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
                      /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
                      /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
                      /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
                      abstract contract ERC20 {
                          /*//////////////////////////////////////////////////////////////
                                                       EVENTS
                          //////////////////////////////////////////////////////////////*/
                          event Transfer(address indexed from, address indexed to, uint256 amount);
                          event Approval(address indexed owner, address indexed spender, uint256 amount);
                          /*//////////////////////////////////////////////////////////////
                                                  METADATA STORAGE
                          //////////////////////////////////////////////////////////////*/
                          string public name;
                          string public symbol;
                          uint8 public immutable decimals;
                          /*//////////////////////////////////////////////////////////////
                                                    ERC20 STORAGE
                          //////////////////////////////////////////////////////////////*/
                          uint256 public totalSupply;
                          mapping(address => uint256) public balanceOf;
                          mapping(address => mapping(address => uint256)) public allowance;
                          /*//////////////////////////////////////////////////////////////
                                                  EIP-2612 STORAGE
                          //////////////////////////////////////////////////////////////*/
                          uint256 internal immutable INITIAL_CHAIN_ID;
                          bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
                          mapping(address => uint256) public nonces;
                          /*//////////////////////////////////////////////////////////////
                                                     CONSTRUCTOR
                          //////////////////////////////////////////////////////////////*/
                          constructor(
                              string memory _name,
                              string memory _symbol,
                              uint8 _decimals
                          ) {
                              name = _name;
                              symbol = _symbol;
                              decimals = _decimals;
                              INITIAL_CHAIN_ID = block.chainid;
                              INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
                          }
                          /*//////////////////////////////////////////////////////////////
                                                     ERC20 LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function approve(address spender, uint256 amount) public virtual returns (bool) {
                              allowance[msg.sender][spender] = amount;
                              emit Approval(msg.sender, spender, amount);
                              return true;
                          }
                          function transfer(address to, uint256 amount) public virtual returns (bool) {
                              balanceOf[msg.sender] -= amount;
                              // Cannot overflow because the sum of all user
                              // balances can't exceed the max uint256 value.
                              unchecked {
                                  balanceOf[to] += amount;
                              }
                              emit Transfer(msg.sender, to, amount);
                              return true;
                          }
                          function transferFrom(
                              address from,
                              address to,
                              uint256 amount
                          ) public virtual returns (bool) {
                              uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
                              if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
                              balanceOf[from] -= amount;
                              // Cannot overflow because the sum of all user
                              // balances can't exceed the max uint256 value.
                              unchecked {
                                  balanceOf[to] += amount;
                              }
                              emit Transfer(from, to, amount);
                              return true;
                          }
                          /*//////////////////////////////////////////////////////////////
                                                   EIP-2612 LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function permit(
                              address owner,
                              address spender,
                              uint256 value,
                              uint256 deadline,
                              uint8 v,
                              bytes32 r,
                              bytes32 s
                          ) public virtual {
                              require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
                              // Unchecked because the only math done is incrementing
                              // the owner's nonce which cannot realistically overflow.
                              unchecked {
                                  address recoveredAddress = ecrecover(
                                      keccak256(
                                          abi.encodePacked(
                                              "\\x19\\x01",
                                              DOMAIN_SEPARATOR(),
                                              keccak256(
                                                  abi.encode(
                                                      keccak256(
                                                          "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                                      ),
                                                      owner,
                                                      spender,
                                                      value,
                                                      nonces[owner]++,
                                                      deadline
                                                  )
                                              )
                                          )
                                      ),
                                      v,
                                      r,
                                      s
                                  );
                                  require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
                                  allowance[recoveredAddress][spender] = value;
                              }
                              emit Approval(owner, spender, value);
                          }
                          function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
                              return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
                          }
                          function computeDomainSeparator() internal view virtual returns (bytes32) {
                              return
                                  keccak256(
                                      abi.encode(
                                          keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                                          keccak256(bytes(name)),
                                          keccak256("1"),
                                          block.chainid,
                                          address(this)
                                      )
                                  );
                          }
                          /*//////////////////////////////////////////////////////////////
                                              INTERNAL MINT/BURN LOGIC
                          //////////////////////////////////////////////////////////////*/
                          function _mint(address to, uint256 amount) internal virtual {
                              totalSupply += amount;
                              // Cannot overflow because the sum of all user
                              // balances can't exceed the max uint256 value.
                              unchecked {
                                  balanceOf[to] += amount;
                              }
                              emit Transfer(address(0), to, amount);
                          }
                          function _burn(address from, uint256 amount) internal virtual {
                              balanceOf[from] -= amount;
                              // Cannot underflow because a user's balance
                              // will never be larger than the total supply.
                              unchecked {
                                  totalSupply -= amount;
                              }
                              emit Transfer(from, address(0), amount);
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity 0.8.17;
                      uint256 constant Bytes1_shift = 0xf8;
                      uint256 constant Bytes4_shift = 0xe0;
                      uint256 constant Bytes20_shift = 0x60;
                      uint256 constant One_word = 0x20;
                      uint256 constant Memory_pointer = 0x40;
                      uint256 constant AssetType_ERC721 = 0;
                      uint256 constant AssetType_ERC1155 = 1;
                      uint256 constant OrderType_ASK = 0;
                      uint256 constant OrderType_BID = 1;
                      uint256 constant Pool_withdrawFrom_selector = 0x9555a94200000000000000000000000000000000000000000000000000000000;
                      uint256 constant Pool_withdrawFrom_from_offset = 0x04;
                      uint256 constant Pool_withdrawFrom_to_offset = 0x24;
                      uint256 constant Pool_withdrawFrom_amount_offset = 0x44;
                      uint256 constant Pool_withdrawFrom_size = 0x64;
                      uint256 constant Pool_deposit_selector = 0xf340fa0100000000000000000000000000000000000000000000000000000000;
                      uint256 constant Pool_deposit_user_offset = 0x04;
                      uint256 constant Pool_deposit_size = 0x24;
                      uint256 constant ERC20_transferFrom_selector = 0x23b872dd00000000000000000000000000000000000000000000000000000000;
                      uint256 constant ERC721_safeTransferFrom_selector = 0x42842e0e00000000000000000000000000000000000000000000000000000000;
                      uint256 constant ERC1155_safeTransferFrom_selector = 0xf242432a00000000000000000000000000000000000000000000000000000000;
                      uint256 constant ERC20_transferFrom_size = 0x64;
                      uint256 constant ERC721_safeTransferFrom_size = 0x64;
                      uint256 constant ERC1155_safeTransferFrom_size = 0xc4;
                      uint256 constant OracleSignatures_size = 0x59;
                      uint256 constant OracleSignatures_s_offset = 0x20;
                      uint256 constant OracleSignatures_v_offset = 0x40;
                      uint256 constant OracleSignatures_blockNumber_offset = 0x41;
                      uint256 constant OracleSignatures_oracle_offset = 0x45;
                      uint256 constant Signatures_size = 0x41;
                      uint256 constant Signatures_s_offset = 0x20;
                      uint256 constant Signatures_v_offset = 0x40;
                      uint256 constant ERC20_transferFrom_from_offset = 0x4;
                      uint256 constant ERC20_transferFrom_to_offset = 0x24;
                      uint256 constant ERC20_transferFrom_amount_offset = 0x44;
                      uint256 constant ERC721_safeTransferFrom_from_offset = 0x4;
                      uint256 constant ERC721_safeTransferFrom_to_offset = 0x24;
                      uint256 constant ERC721_safeTransferFrom_id_offset = 0x44;
                      uint256 constant ERC1155_safeTransferFrom_from_offset = 0x4;
                      uint256 constant ERC1155_safeTransferFrom_to_offset = 0x24;
                      uint256 constant ERC1155_safeTransferFrom_id_offset = 0x44;
                      uint256 constant ERC1155_safeTransferFrom_amount_offset = 0x64;
                      uint256 constant ERC1155_safeTransferFrom_data_pointer_offset = 0x84;
                      uint256 constant ERC1155_safeTransferFrom_data_offset = 0xa4;
                      uint256 constant Delegate_transfer_selector = 0xa1ccb98e00000000000000000000000000000000000000000000000000000000;
                      uint256 constant Delegate_transfer_calldata_offset = 0x1c;
                      uint256 constant Order_size = 0x100;
                      uint256 constant Order_trader_offset = 0x00;
                      uint256 constant Order_collection_offset = 0x20;
                      uint256 constant Order_listingsRoot_offset = 0x40;
                      uint256 constant Order_numberOfListings_offset = 0x60;
                      uint256 constant Order_expirationTime_offset = 0x80;
                      uint256 constant Order_assetType_offset = 0xa0;
                      uint256 constant Order_makerFee_offset = 0xc0;
                      uint256 constant Order_salt_offset = 0xe0;
                      uint256 constant Exchange_size = 0x80;
                      uint256 constant Exchange_askIndex_offset = 0x00;
                      uint256 constant Exchange_proof_offset = 0x20;
                      uint256 constant Exchange_maker_offset = 0x40;
                      uint256 constant Exchange_taker_offset = 0x60;
                      uint256 constant BidExchange_size = 0x80;
                      uint256 constant BidExchange_askIndex_offset = 0x00;
                      uint256 constant BidExchange_proof_offset = 0x20;
                      uint256 constant BidExchange_maker_offset = 0x40;
                      uint256 constant BidExchange_taker_offset = 0x60;
                      uint256 constant Listing_size = 0x80;
                      uint256 constant Listing_index_offset = 0x00;
                      uint256 constant Listing_tokenId_offset = 0x20;
                      uint256 constant Listing_amount_offset = 0x40;
                      uint256 constant Listing_price_offset = 0x60;
                      uint256 constant Taker_size = 0x40;
                      uint256 constant Taker_tokenId_offset = 0x00;
                      uint256 constant Taker_amount_offset = 0x20;
                      uint256 constant StateUpdate_size = 0x80;
                      uint256 constant StateUpdate_salt_offset = 0x20;
                      uint256 constant StateUpdate_leaf_offset = 0x40;
                      uint256 constant StateUpdate_value_offset = 0x60;
                      uint256 constant Transfer_size = 0xa0;
                      uint256 constant Transfer_trader_offset = 0x00;
                      uint256 constant Transfer_id_offset = 0x20;
                      uint256 constant Transfer_amount_offset = 0x40;
                      uint256 constant Transfer_collection_offset = 0x60;
                      uint256 constant Transfer_assetType_offset = 0x80;
                      uint256 constant ExecutionBatch_selector_offset = 0x20;
                      uint256 constant ExecutionBatch_calldata_offset = 0x40;
                      uint256 constant ExecutionBatch_base_size = 0xa0; // size of the executionBatch without the flattened dynamic elements
                      uint256 constant ExecutionBatch_taker_offset = 0x00;
                      uint256 constant ExecutionBatch_orderType_offset = 0x20;
                      uint256 constant ExecutionBatch_transfers_pointer_offset = 0x40;
                      uint256 constant ExecutionBatch_length_offset = 0x60;
                      uint256 constant ExecutionBatch_transfers_offset = 0x80;
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.17;
                      struct TakeAsk {
                          Order[] orders;
                          Exchange[] exchanges;
                          FeeRate takerFee;
                          bytes signatures;
                          address tokenRecipient;
                      }
                      struct TakeAskSingle {
                          Order order;
                          Exchange exchange;
                          FeeRate takerFee;
                          bytes signature;
                          address tokenRecipient;
                      }
                      struct TakeBid {
                          Order[] orders;
                          Exchange[] exchanges;
                          FeeRate takerFee;
                          bytes signatures;
                      }
                      struct TakeBidSingle {
                          Order order;
                          Exchange exchange;
                          FeeRate takerFee;
                          bytes signature;
                      }
                      enum AssetType {
                          ERC721,
                          ERC1155
                      }
                      enum OrderType {
                          ASK,
                          BID
                      }
                      struct Exchange { // Size: 0x80
                          uint256 index; // 0x00
                          bytes32[] proof; // 0x20
                          Listing listing; // 0x40
                          Taker taker; // 0x60
                      }
                      struct Listing { // Size: 0x80
                          uint256 index; // 0x00
                          uint256 tokenId; // 0x20
                          uint256 amount; // 0x40
                          uint256 price; // 0x60
                      }
                      struct Taker { // Size: 0x40
                          uint256 tokenId; // 0x00
                          uint256 amount; // 0x20
                      }
                      struct Order { // Size: 0x100
                          address trader; // 0x00
                          address collection; // 0x20
                          bytes32 listingsRoot; // 0x40
                          uint256 numberOfListings; // 0x60
                          uint256 expirationTime; // 0x80
                          AssetType assetType; // 0xa0
                          FeeRate makerFee; // 0xc0
                          uint256 salt; // 0xe0
                      }
                      /*
                      Reference only; struct is composed manually using calldata formatting in execution
                      struct ExecutionBatch { // Size: 0x80
                          address taker; // 0x00
                          OrderType orderType; // 0x20
                          Transfer[] transfers; // 0x40
                          uint256 length; // 0x60
                      }
                      */
                      struct Transfer { // Size: 0xa0
                          address trader; // 0x00
                          uint256 id; // 0x20
                          uint256 amount; // 0x40
                          address collection; // 0x60
                          AssetType assetType; // 0x80
                      }
                      struct FungibleTransfers {
                          uint256 totalProtocolFee;
                          uint256 totalSellerTransfer;
                          uint256 totalTakerFee;
                          uint256 feeRecipientId;
                          uint256 makerId;
                          address[] feeRecipients;
                          address[] makers;
                          uint256[] makerTransfers;
                          uint256[] feeTransfers;
                          AtomicExecution[] executions;
                      }
                      struct AtomicExecution { // Size: 0xe0
                          uint256 makerId; // 0x00
                          uint256 sellerAmount; // 0x20
                          uint256 makerFeeRecipientId; // 0x40
                          uint256 makerFeeAmount; // 0x60
                          uint256 takerFeeAmount; // 0x80
                          uint256 protocolFeeAmount; // 0xa0
                          StateUpdate stateUpdate; // 0xc0
                      }
                      struct StateUpdate { // Size: 0xa0
                          address trader; // 0x00
                          bytes32 hash; // 0x20
                          uint256 index; // 0x40
                          uint256 value; // 0x60
                          uint256 maxAmount; // 0x80
                      }
                      struct Fees { // Size: 0x40
                          FeeRate protocolFee; // 0x00
                          FeeRate takerFee; // 0x20
                      }
                      struct FeeRate { // Size: 0x40
                          address recipient; // 0x00
                          uint16 rate; // 0x20
                      }
                      struct Cancel {
                          bytes32 hash;
                          uint256 index;
                          uint256 amount;
                      }
                      

                      File 4 of 6: UtilityWenUpgradeable
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
                      pragma solidity ^0.8.0;
                      import "../utils/ContextUpgradeable.sol";
                      import "../proxy/utils/Initializable.sol";
                      /**
                       * @dev Contract module which provides a basic access control mechanism, where
                       * there is an account (an owner) that can be granted exclusive access to
                       * specific functions.
                       *
                       * By default, the owner account will be the one that deploys the contract. This
                       * can later be changed with {transferOwnership}.
                       *
                       * This module is used through inheritance. It will make available the modifier
                       * `onlyOwner`, which can be applied to your functions to restrict their use to
                       * the owner.
                       */
                      abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
                          address private _owner;
                          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                          /**
                           * @dev Initializes the contract setting the deployer as the initial owner.
                           */
                          function __Ownable_init() internal onlyInitializing {
                              __Ownable_init_unchained();
                          }
                          function __Ownable_init_unchained() internal onlyInitializing {
                              _transferOwnership(_msgSender());
                          }
                          /**
                           * @dev Throws if called by any account other than the owner.
                           */
                          modifier onlyOwner() {
                              _checkOwner();
                              _;
                          }
                          /**
                           * @dev Returns the address of the current owner.
                           */
                          function owner() public view virtual returns (address) {
                              return _owner;
                          }
                          /**
                           * @dev Throws if the sender is not the owner.
                           */
                          function _checkOwner() internal view virtual {
                              require(owner() == _msgSender(), "Ownable: caller is not the owner");
                          }
                          /**
                           * @dev Leaves the contract without owner. It will not be possible to call
                           * `onlyOwner` functions 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);
                          }
                          /**
                           * @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.6.0) (interfaces/IERC2981.sol)
                      pragma solidity ^0.8.0;
                      import "../utils/introspection/IERC165Upgradeable.sol";
                      /**
                       * @dev Interface for the NFT Royalty Standard.
                       *
                       * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
                       * support for royalty payments across all NFT marketplaces and ecosystem participants.
                       *
                       * _Available since v4.5._
                       */
                      interface IERC2981Upgradeable is IERC165Upgradeable {
                          /**
                           * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
                           * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
                           */
                          function royaltyInfo(uint256 tokenId, uint256 salePrice)
                              external
                              view
                              returns (address receiver, uint256 royaltyAmount);
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
                      pragma solidity ^0.8.2;
                      import "../../utils/AddressUpgradeable.sol";
                      /**
                       * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                       * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
                       * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                       * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                       *
                       * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
                       * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
                       * case an upgrade adds a module that needs to be initialized.
                       *
                       * For example:
                       *
                       * [.hljs-theme-light.nopadding]
                       * ```
                       * contract MyToken is ERC20Upgradeable {
                       *     function initialize() initializer public {
                       *         __ERC20_init("MyToken", "MTK");
                       *     }
                       * }
                       * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
                       *     function initializeV2() reinitializer(2) public {
                       *         __ERC20Permit_init("MyToken");
                       *     }
                       * }
                       * ```
                       *
                       * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                       * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                       *
                       * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                       * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                       *
                       * [CAUTION]
                       * ====
                       * Avoid leaving a contract uninitialized.
                       *
                       * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                       * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
                       * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
                       *
                       * [.hljs-theme-light.nopadding]
                       * ```
                       * /// @custom:oz-upgrades-unsafe-allow constructor
                       * constructor() {
                       *     _disableInitializers();
                       * }
                       * ```
                       * ====
                       */
                      abstract contract Initializable {
                          /**
                           * @dev Indicates that the contract has been initialized.
                           * @custom:oz-retyped-from bool
                           */
                          uint8 private _initialized;
                          /**
                           * @dev Indicates that the contract is in the process of being initialized.
                           */
                          bool private _initializing;
                          /**
                           * @dev Triggered when the contract has been initialized or reinitialized.
                           */
                          event Initialized(uint8 version);
                          /**
                           * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                           * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
                           */
                          modifier initializer() {
                              bool isTopLevelCall = !_initializing;
                              require(
                                  (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                                  "Initializable: contract is already initialized"
                              );
                              _initialized = 1;
                              if (isTopLevelCall) {
                                  _initializing = true;
                              }
                              _;
                              if (isTopLevelCall) {
                                  _initializing = false;
                                  emit Initialized(1);
                              }
                          }
                          /**
                           * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                           * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                           * used to initialize parent contracts.
                           *
                           * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
                           * initialization step. This is essential to configure modules that are added through upgrades and that require
                           * initialization.
                           *
                           * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                           * a contract, executing them in the right order is up to the developer or operator.
                           */
                          modifier reinitializer(uint8 version) {
                              require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                              _initialized = version;
                              _initializing = true;
                              _;
                              _initializing = false;
                              emit Initialized(version);
                          }
                          /**
                           * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                           * {initializer} and {reinitializer} modifiers, directly or indirectly.
                           */
                          modifier onlyInitializing() {
                              require(_initializing, "Initializable: contract is not initializing");
                              _;
                          }
                          /**
                           * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                           * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                           * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                           * through proxies.
                           */
                          function _disableInitializers() internal virtual {
                              require(!_initializing, "Initializable: contract is initializing");
                              if (_initialized < type(uint8).max) {
                                  _initialized = type(uint8).max;
                                  emit Initialized(type(uint8).max);
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)
                      pragma solidity ^0.8.0;
                      import "../../interfaces/IERC2981Upgradeable.sol";
                      import "../../utils/introspection/ERC165Upgradeable.sol";
                      import "../../proxy/utils/Initializable.sol";
                      /**
                       * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
                       *
                       * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
                       * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
                       *
                       * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
                       * fee is specified in basis points by default.
                       *
                       * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
                       * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
                       * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
                       *
                       * _Available since v4.5._
                       */
                      abstract contract ERC2981Upgradeable is Initializable, IERC2981Upgradeable, ERC165Upgradeable {
                          function __ERC2981_init() internal onlyInitializing {
                          }
                          function __ERC2981_init_unchained() internal onlyInitializing {
                          }
                          struct RoyaltyInfo {
                              address receiver;
                              uint96 royaltyFraction;
                          }
                          RoyaltyInfo private _defaultRoyaltyInfo;
                          mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
                          /**
                           * @dev See {IERC165-supportsInterface}.
                           */
                          function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165Upgradeable, ERC165Upgradeable) returns (bool) {
                              return interfaceId == type(IERC2981Upgradeable).interfaceId || super.supportsInterface(interfaceId);
                          }
                          /**
                           * @inheritdoc IERC2981Upgradeable
                           */
                          function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
                              RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];
                              if (royalty.receiver == address(0)) {
                                  royalty = _defaultRoyaltyInfo;
                              }
                              uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();
                              return (royalty.receiver, royaltyAmount);
                          }
                          /**
                           * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
                           * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
                           * override.
                           */
                          function _feeDenominator() internal pure virtual returns (uint96) {
                              return 10000;
                          }
                          /**
                           * @dev Sets the royalty information that all ids in this contract will default to.
                           *
                           * Requirements:
                           *
                           * - `receiver` cannot be the zero address.
                           * - `feeNumerator` cannot be greater than the fee denominator.
                           */
                          function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
                              require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
                              require(receiver != address(0), "ERC2981: invalid receiver");
                              _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
                          }
                          /**
                           * @dev Removes default royalty information.
                           */
                          function _deleteDefaultRoyalty() internal virtual {
                              delete _defaultRoyaltyInfo;
                          }
                          /**
                           * @dev Sets the royalty information for a specific token id, overriding the global default.
                           *
                           * Requirements:
                           *
                           * - `receiver` cannot be the zero address.
                           * - `feeNumerator` cannot be greater than the fee denominator.
                           */
                          function _setTokenRoyalty(
                              uint256 tokenId,
                              address receiver,
                              uint96 feeNumerator
                          ) internal virtual {
                              require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
                              require(receiver != address(0), "ERC2981: Invalid parameters");
                              _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
                          }
                          /**
                           * @dev Resets royalty information for the token id back to the global default.
                           */
                          function _resetTokenRoyalty(uint256 tokenId) internal virtual {
                              delete _tokenRoyaltyInfo[tokenId];
                          }
                          /**
                           * @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[48] private __gap;
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
                      pragma solidity ^0.8.1;
                      /**
                       * @dev Collection of functions related to the address type
                       */
                      library 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
                                      /// @solidity memory-safe-assembly
                                      assembly {
                                          let returndata_size := mload(returndata)
                                          revert(add(32, returndata), returndata_size)
                                      }
                                  } else {
                                      revert(errorMessage);
                                  }
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts 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 (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev These functions deal with verification of Merkle Tree proofs.
                       *
                       * The proofs can be generated using the JavaScript library
                       * https://github.com/miguelmota/merkletreejs[merkletreejs].
                       * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
                       *
                       * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
                       *
                       * WARNING: You should avoid using leaf values that are 64 bytes long prior to
                       * hashing, or use a hash function other than keccak256 for hashing leaves.
                       * This is because the concatenation of a sorted pair of internal nodes in
                       * the merkle tree could be reinterpreted as a leaf value.
                       */
                      library MerkleProofUpgradeable {
                          /**
                           * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
                           * defined by `root`. For this, a `proof` must be provided, containing
                           * sibling hashes on the branch from the leaf to the root of the tree. Each
                           * pair of leaves and each pair of pre-images are assumed to be sorted.
                           */
                          function verify(
                              bytes32[] memory proof,
                              bytes32 root,
                              bytes32 leaf
                          ) internal pure returns (bool) {
                              return processProof(proof, leaf) == root;
                          }
                          /**
                           * @dev Calldata version of {verify}
                           *
                           * _Available since v4.7._
                           */
                          function verifyCalldata(
                              bytes32[] calldata proof,
                              bytes32 root,
                              bytes32 leaf
                          ) internal pure returns (bool) {
                              return processProofCalldata(proof, leaf) == root;
                          }
                          /**
                           * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
                           * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
                           * hash matches the root of the tree. When processing the proof, the pairs
                           * of leafs & pre-images are assumed to be sorted.
                           *
                           * _Available since v4.4._
                           */
                          function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
                              bytes32 computedHash = leaf;
                              for (uint256 i = 0; i < proof.length; i++) {
                                  computedHash = _hashPair(computedHash, proof[i]);
                              }
                              return computedHash;
                          }
                          /**
                           * @dev Calldata version of {processProof}
                           *
                           * _Available since v4.7._
                           */
                          function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
                              bytes32 computedHash = leaf;
                              for (uint256 i = 0; i < proof.length; i++) {
                                  computedHash = _hashPair(computedHash, proof[i]);
                              }
                              return computedHash;
                          }
                          /**
                           * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by
                           * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
                           *
                           * _Available since v4.7._
                           */
                          function multiProofVerify(
                              bytes32[] memory proof,
                              bool[] memory proofFlags,
                              bytes32 root,
                              bytes32[] memory leaves
                          ) internal pure returns (bool) {
                              return processMultiProof(proof, proofFlags, leaves) == root;
                          }
                          /**
                           * @dev Calldata version of {multiProofVerify}
                           *
                           * _Available since v4.7._
                           */
                          function multiProofVerifyCalldata(
                              bytes32[] calldata proof,
                              bool[] calldata proofFlags,
                              bytes32 root,
                              bytes32[] memory leaves
                          ) internal pure returns (bool) {
                              return processMultiProofCalldata(proof, proofFlags, leaves) == root;
                          }
                          /**
                           * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,
                           * consuming from one or the other at each step according to the instructions given by
                           * `proofFlags`.
                           *
                           * _Available since v4.7._
                           */
                          function processMultiProof(
                              bytes32[] memory proof,
                              bool[] memory proofFlags,
                              bytes32[] memory leaves
                          ) internal pure returns (bytes32 merkleRoot) {
                              // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
                              // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
                              // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
                              // the merkle tree.
                              uint256 leavesLen = leaves.length;
                              uint256 totalHashes = proofFlags.length;
                              // Check proof validity.
                              require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
                              // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
                              // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
                              bytes32[] memory hashes = new bytes32[](totalHashes);
                              uint256 leafPos = 0;
                              uint256 hashPos = 0;
                              uint256 proofPos = 0;
                              // At each step, we compute the next hash using two values:
                              // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
                              //   get the next hash.
                              // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
                              //   `proof` array.
                              for (uint256 i = 0; i < totalHashes; i++) {
                                  bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                                  bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
                                  hashes[i] = _hashPair(a, b);
                              }
                              if (totalHashes > 0) {
                                  return hashes[totalHashes - 1];
                              } else if (leavesLen > 0) {
                                  return leaves[0];
                              } else {
                                  return proof[0];
                              }
                          }
                          /**
                           * @dev Calldata version of {processMultiProof}
                           *
                           * _Available since v4.7._
                           */
                          function processMultiProofCalldata(
                              bytes32[] calldata proof,
                              bool[] calldata proofFlags,
                              bytes32[] memory leaves
                          ) internal pure returns (bytes32 merkleRoot) {
                              // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
                              // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
                              // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
                              // the merkle tree.
                              uint256 leavesLen = leaves.length;
                              uint256 totalHashes = proofFlags.length;
                              // Check proof validity.
                              require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
                              // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
                              // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
                              bytes32[] memory hashes = new bytes32[](totalHashes);
                              uint256 leafPos = 0;
                              uint256 hashPos = 0;
                              uint256 proofPos = 0;
                              // At each step, we compute the next hash using two values:
                              // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
                              //   get the next hash.
                              // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
                              //   `proof` array.
                              for (uint256 i = 0; i < totalHashes; i++) {
                                  bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                                  bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
                                  hashes[i] = _hashPair(a, b);
                              }
                              if (totalHashes > 0) {
                                  return hashes[totalHashes - 1];
                              } else if (leavesLen > 0) {
                                  return leaves[0];
                              } else {
                                  return proof[0];
                              }
                          }
                          function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
                              return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
                          }
                          function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  mstore(0x00, a)
                                  mstore(0x20, b)
                                  value := keccak256(0x00, 0x40)
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
                      pragma solidity ^0.8.0;
                      import "./IERC165Upgradeable.sol";
                      import "../../proxy/utils/Initializable.sol";
                      /**
                       * @dev Implementation of the {IERC165} interface.
                       *
                       * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
                       * for the additional interface id that will be supported. For example:
                       *
                       * ```solidity
                       * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                       *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
                       * }
                       * ```
                       *
                       * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
                       */
                      abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
                          function __ERC165_init() internal onlyInitializing {
                          }
                          function __ERC165_init_unchained() internal onlyInitializing {
                          }
                          /**
                           * @dev See {IERC165-supportsInterface}.
                           */
                          function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                              return interfaceId == type(IERC165Upgradeable).interfaceId;
                          }
                          /**
                           * @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/introspection/IERC165.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev Interface of the ERC165 standard, as defined in the
                       * https://eips.ethereum.org/EIPS/eip-165[EIP].
                       *
                       * Implementers can declare support of contract interfaces, which can then be
                       * queried by others ({ERC165Checker}).
                       *
                       * For an implementation, see {ERC165}.
                       */
                      interface IERC165Upgradeable {
                          /**
                           * @dev Returns true if this contract implements the interface defined by
                           * `interfaceId`. See the corresponding
                           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                           * to learn more about how these ids are created.
                           *
                           * This function call must use less than 30 000 gas.
                           */
                          function supportsInterface(bytes4 interfaceId) external view returns (bool);
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev String operations.
                       */
                      library StringsUpgradeable {
                          bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
                          uint8 private constant _ADDRESS_LENGTH = 20;
                          /**
                           * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                           */
                          function toString(uint256 value) internal pure returns (string memory) {
                              // Inspired by OraclizeAPI's implementation - MIT licence
                              // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                              if (value == 0) {
                                  return "0";
                              }
                              uint256 temp = value;
                              uint256 digits;
                              while (temp != 0) {
                                  digits++;
                                  temp /= 10;
                              }
                              bytes memory buffer = new bytes(digits);
                              while (value != 0) {
                                  digits -= 1;
                                  buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                                  value /= 10;
                              }
                              return string(buffer);
                          }
                          /**
                           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                           */
                          function toHexString(uint256 value) internal pure returns (string memory) {
                              if (value == 0) {
                                  return "0x00";
                              }
                              uint256 temp = value;
                              uint256 length = 0;
                              while (temp != 0) {
                                  length++;
                                  temp >>= 8;
                              }
                              return toHexString(value, length);
                          }
                          /**
                           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                           */
                          function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                              bytes memory buffer = new bytes(2 * length + 2);
                              buffer[0] = "0";
                              buffer[1] = "x";
                              for (uint256 i = 2 * length + 1; i > 1; --i) {
                                  buffer[i] = _HEX_SYMBOLS[value & 0xf];
                                  value >>= 4;
                              }
                              require(value == 0, "Strings: hex length insufficient");
                              return string(buffer);
                          }
                          /**
                           * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
                           */
                          function toHexString(address addr) internal pure returns (string memory) {
                              return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.4;
                      /// @notice Optimized and flexible operator filterer to abide to OpenSea's
                      /// mandatory on-chain royalty enforcement in order for new collections to
                      /// receive royalties.
                      /// For more information, see:
                      /// See: https://github.com/ProjectOpenSea/operator-filter-registry
                      abstract contract OperatorFilterer {
                          /// @dev The default OpenSea operator blocklist subscription.
                          address internal constant _DEFAULT_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6;
                          /// @dev The OpenSea operator filter registry.
                          address internal constant _OPERATOR_FILTER_REGISTRY = 0x000000000000AAeB6D7670E522A718067333cd4E;
                          /// @dev Registers the current contract to OpenSea's operator filter,
                          /// and subscribe to the default OpenSea operator blocklist.
                          /// Note: Will not revert nor update existing settings for repeated registration.
                          function _registerForOperatorFiltering() internal virtual {
                              _registerForOperatorFiltering(_DEFAULT_SUBSCRIPTION, true);
                          }
                          /// @dev Registers the current contract to OpenSea's operator filter.
                          /// Note: Will not revert nor update existing settings for repeated registration.
                          function _registerForOperatorFiltering(address subscriptionOrRegistrantToCopy, bool subscribe)
                              internal
                              virtual
                          {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  let functionSelector := 0x7d3e3dbe // `registerAndSubscribe(address,address)`.
                                  // Clean the upper 96 bits of `subscriptionOrRegistrantToCopy` in case they are dirty.
                                  subscriptionOrRegistrantToCopy := shr(96, shl(96, subscriptionOrRegistrantToCopy))
                                  for {} iszero(subscribe) {} {
                                      if iszero(subscriptionOrRegistrantToCopy) {
                                          functionSelector := 0x4420e486 // `register(address)`.
                                          break
                                      }
                                      functionSelector := 0xa0af2903 // `registerAndCopyEntries(address,address)`.
                                      break
                                  }
                                  // Store the function selector.
                                  mstore(0x00, shl(224, functionSelector))
                                  // Store the `address(this)`.
                                  mstore(0x04, address())
                                  // Store the `subscriptionOrRegistrantToCopy`.
                                  mstore(0x24, subscriptionOrRegistrantToCopy)
                                  // Register into the registry.
                                  if iszero(call(gas(), _OPERATOR_FILTER_REGISTRY, 0, 0x00, 0x44, 0x00, 0x04)) {
                                      // If the function selector has not been overwritten,
                                      // it is an out-of-gas error.
                                      if eq(shr(224, mload(0x00)), functionSelector) {
                                          // To prevent gas under-estimation.
                                          revert(0, 0)
                                      }
                                  }
                                  // Restore the part of the free memory pointer that was overwritten,
                                  // which is guaranteed to be zero, because of Solidity's memory size limits.
                                  mstore(0x24, 0)
                              }
                          }
                          /// @dev Modifier to guard a function and revert if the caller is a blocked operator.
                          modifier onlyAllowedOperator(address from) virtual {
                              if (from != msg.sender) {
                                  if (!_isPriorityOperator(msg.sender)) {
                                      if (_operatorFilteringEnabled()) _revertIfBlocked(msg.sender);
                                  }
                              }
                              _;
                          }
                          /// @dev Modifier to guard a function from approving a blocked operator..
                          modifier onlyAllowedOperatorApproval(address operator) virtual {
                              if (!_isPriorityOperator(operator)) {
                                  if (_operatorFilteringEnabled()) _revertIfBlocked(operator);
                              }
                              _;
                          }
                          /// @dev Helper function that reverts if the `operator` is blocked by the registry.
                          function _revertIfBlocked(address operator) private view {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  // Store the function selector of `isOperatorAllowed(address,address)`,
                                  // shifted left by 6 bytes, which is enough for 8tb of memory.
                                  // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL).
                                  mstore(0x00, 0xc6171134001122334455)
                                  // Store the `address(this)`.
                                  mstore(0x1a, address())
                                  // Store the `operator`.
                                  mstore(0x3a, operator)
                                  // `isOperatorAllowed` always returns true if it does not revert.
                                  if iszero(staticcall(gas(), _OPERATOR_FILTER_REGISTRY, 0x16, 0x44, 0x00, 0x00)) {
                                      // Bubble up the revert if the staticcall reverts.
                                      returndatacopy(0x00, 0x00, returndatasize())
                                      revert(0x00, returndatasize())
                                  }
                                  // We'll skip checking if `from` is inside the blacklist.
                                  // Even though that can block transferring out of wrapper contracts,
                                  // we don't want tokens to be stuck.
                                  // Restore the part of the free memory pointer that was overwritten,
                                  // which is guaranteed to be zero, if less than 8tb of memory is used.
                                  mstore(0x3a, 0)
                              }
                          }
                          /// @dev For deriving contracts to override, so that operator filtering
                          /// can be turned on / off.
                          /// Returns true by default.
                          function _operatorFilteringEnabled() internal view virtual returns (bool) {
                              return true;
                          }
                          /// @dev For deriving contracts to override, so that preferred marketplaces can
                          /// skip operator filtering, helping users save gas.
                          /// Returns false for all inputs by default.
                          function _isPriorityOperator(address) internal view virtual returns (bool) {
                              return false;
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.2;
                      import "./ILayerZeroUserApplicationConfigUpgradeable.sol";
                      interface ILayerZeroEndpointUpgradeable is ILayerZeroUserApplicationConfigUpgradeable {
                          // @notice send a LayerZero message to the specified address at a LayerZero endpoint.
                          // @param _dstChainId - the destination chain identifier
                          // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
                          // @param _payload - a custom bytes payload to send to the destination contract
                          // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
                          // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
                          // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination
                          function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
                          // @notice used by the messaging library to publish verified payload
                          // @param _srcChainId - the source chain identifier
                          // @param _srcAddress - the source contract (as bytes) at the source chain
                          // @param _dstAddress - the address on destination chain
                          // @param _nonce - the unbound message ordering nonce
                          // @param _gasLimit - the gas limit for external contract execution
                          // @param _payload - verified payload to send to the destination contract
                          function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;
                          // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain
                          // @param _srcChainId - the source chain identifier
                          // @param _srcAddress - the source chain contract address
                          function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);
                          // @notice get the outboundNonce from this source chain which, consequently, is always an EVM
                          // @param _srcAddress - the source chain contract address
                          function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);
                          // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
                          // @param _dstChainId - the destination chain identifier
                          // @param _userApplication - the user app address on this EVM chain
                          // @param _payload - the custom message to send over LayerZero
                          // @param _payInZRO - if false, user app pays the protocol fee in native token
                          // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
                          function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);
                          // @notice get this Endpoint's immutable source identifier
                          function getChainId() external view returns (uint16);
                          // @notice the interface to retry failed message on this Endpoint destination
                          // @param _srcChainId - the source chain identifier
                          // @param _srcAddress - the source chain contract address
                          // @param _payload - the payload to be retried
                          function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;
                          // @notice query if any STORED payload (message blocking) at the endpoint.
                          // @param _srcChainId - the source chain identifier
                          // @param _srcAddress - the source chain contract address
                          function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);
                          // @notice query if the _libraryAddress is valid for sending msgs.
                          // @param _userApplication - the user app address on this EVM chain
                          function getSendLibraryAddress(address _userApplication) external view returns (address);
                          // @notice query if the _libraryAddress is valid for receiving msgs.
                          // @param _userApplication - the user app address on this EVM chain
                          function getReceiveLibraryAddress(address _userApplication) external view returns (address);
                          // @notice query if the non-reentrancy guard for send() is on
                          // @return true if the guard is on. false otherwise
                          function isSendingPayload() external view returns (bool);
                          // @notice query if the non-reentrancy guard for receive() is on
                          // @return true if the guard is on. false otherwise
                          function isReceivingPayload() external view returns (bool);
                          // @notice get the configuration of the LayerZero messaging library of the specified version
                          // @param _version - messaging library version
                          // @param _chainId - the chainId for the pending config change
                          // @param _userApplication - the contract address of the user application
                          // @param _configType - type of configuration. every messaging library has its own convention.
                          function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);
                          // @notice get the send() LayerZero messaging library version
                          // @param _userApplication - the contract address of the user application
                          function getSendVersion(address _userApplication) external view returns (uint16);
                          // @notice get the lzReceive() LayerZero messaging library version
                          // @param _userApplication - the contract address of the user application
                          function getReceiveVersion(address _userApplication) external view returns (uint16);
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.2;
                      interface ILayerZeroReceiverUpgradeable {
                          // @notice LayerZero endpoint will invoke this function to deliver the message on the destination
                          // @param _srcChainId - the source endpoint identifier
                          // @param _srcAddress - the source sending contract address from the source chain
                          // @param _nonce - the ordered message nonce
                          // @param _payload - the signed payload is the UA bytes has encoded to be sent
                          function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.2;
                      interface ILayerZeroUserApplicationConfigUpgradeable {
                          // @notice set the configuration of the LayerZero messaging library of the specified version
                          // @param _version - messaging library version
                          // @param _chainId - the chainId for the pending config change
                          // @param _configType - type of configuration. every messaging library has its own convention.
                          // @param _config - configuration in the bytes. can encode arbitrary content.
                          function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;
                          // @notice set the send() LayerZero messaging library version to _version
                          // @param _version - new messaging library version
                          function setSendVersion(uint16 _version) external;
                          // @notice set the lzReceive() LayerZero messaging library version to _version
                          // @param _version - new messaging library version
                          function setReceiveVersion(uint16 _version) external;
                          // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
                          // @param _srcChainId - the chainId of the source chain
                          // @param _srcAddress - the contract address of the source contract at the source chain
                          function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.2;
                      import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
                      import "../interfaces/ILayerZeroReceiverUpgradeable.sol";
                      import "../interfaces/ILayerZeroUserApplicationConfigUpgradeable.sol";
                      import "../interfaces/ILayerZeroEndpointUpgradeable.sol";
                      import "../../util/BytesLib.sol";
                      /*
                       * a generic LzReceiver implementation
                       */
                      abstract contract LzAppUpgradeable is Initializable, OwnableUpgradeable, ILayerZeroReceiverUpgradeable, ILayerZeroUserApplicationConfigUpgradeable {
                          using BytesLib for bytes;
                          // ua can not send payload larger than this by default, but it can be changed by the ua owner
                          uint constant public DEFAULT_PAYLOAD_SIZE_LIMIT = 10000;
                          ILayerZeroEndpointUpgradeable public lzEndpoint;
                          mapping(uint16 => bytes) public trustedRemoteLookup;
                          mapping(uint16 => mapping(uint16 => uint)) public minDstGasLookup;
                          mapping(uint16 => uint) public payloadSizeLimitLookup;
                          address public precrime;
                          event SetPrecrime(address precrime);
                          event SetTrustedRemote(uint16 _remoteChainId, bytes _path);
                          event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);
                          event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas);
                          function __LzAppUpgradeable_init(address _endpoint) internal onlyInitializing {
                              __Ownable_init_unchained();
                              __LzAppUpgradeable_init_unchained(_endpoint);
                          }
                          function __LzAppUpgradeable_init_unchained(address _endpoint) internal onlyInitializing {
                              lzEndpoint = ILayerZeroEndpointUpgradeable(_endpoint);
                          }
                          function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public virtual override {
                              // lzReceive must be called by the endpoint for security
                              require(_msgSender() == address(lzEndpoint), "LzApp: invalid endpoint caller");
                              bytes memory trustedRemote = trustedRemoteLookup[_srcChainId];
                              // if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote.
                              require(_srcAddress.length == trustedRemote.length && trustedRemote.length > 0 && keccak256(_srcAddress) == keccak256(trustedRemote), "LzApp: invalid source sending contract");
                              _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
                          }
                          // abstract function - the default behaviour of LayerZero is blocking. See: NonblockingLzApp if you dont need to enforce ordered messaging
                          function _blockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual;
                          function _lzSend(uint16 _dstChainId, bytes memory _payload, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams, uint _nativeFee) internal virtual {
                              bytes memory trustedRemote = trustedRemoteLookup[_dstChainId];
                              require(trustedRemote.length != 0, "LzApp: destination chain is not a trusted source");
                              _checkPayloadSize(_dstChainId, _payload.length);
                              lzEndpoint.send{value: _nativeFee}(_dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);
                          }
                          function _checkGasLimit(uint16 _dstChainId, uint16 _type, bytes memory _adapterParams, uint _extraGas) internal view virtual {
                              uint providedGasLimit = _getGasLimit(_adapterParams);
                              uint minGasLimit = minDstGasLookup[_dstChainId][_type] + _extraGas;
                              require(minGasLimit > 0, "LzApp: minGasLimit not set");
                              require(providedGasLimit >= minGasLimit, "LzApp: gas limit is too low");
                          }
                          function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint gasLimit) {
                              require(_adapterParams.length >= 34, "LzApp: invalid adapterParams");
                              assembly {
                                  gasLimit := mload(add(_adapterParams, 34))
                              }
                          }
                          function _checkPayloadSize(uint16 _dstChainId, uint _payloadSize) internal view virtual {
                              uint payloadSizeLimit = payloadSizeLimitLookup[_dstChainId];
                              if (payloadSizeLimit == 0) { // use default if not set
                                  payloadSizeLimit = DEFAULT_PAYLOAD_SIZE_LIMIT;
                              }
                              require(_payloadSize <= payloadSizeLimit, "LzApp: payload size is too large");
                          }
                          //---------------------------UserApplication config----------------------------------------
                          function getConfig(uint16 _version, uint16 _chainId, address, uint _configType) external view returns (bytes memory) {
                              return lzEndpoint.getConfig(_version, _chainId, address(this), _configType);
                          }
                          // generic config for LayerZero user Application
                          function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external override onlyOwner {
                              lzEndpoint.setConfig(_version, _chainId, _configType, _config);
                          }
                          function setSendVersion(uint16 _version) external override onlyOwner {
                              lzEndpoint.setSendVersion(_version);
                          }
                          function setReceiveVersion(uint16 _version) external override onlyOwner {
                              lzEndpoint.setReceiveVersion(_version);
                          }
                          function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner {
                              lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);
                          }
                          // _path = abi.encodePacked(remoteAddress, localAddress)
                          // this function set the trusted path for the cross-chain communication
                          function setTrustedRemote(uint16 _srcChainId, bytes calldata _path) external onlyOwner {
                              trustedRemoteLookup[_srcChainId] = _path;
                              emit SetTrustedRemote(_srcChainId, _path);
                          }
                          function setTrustedRemoteAddress(uint16 _remoteChainId, bytes calldata _remoteAddress) external onlyOwner {
                              trustedRemoteLookup[_remoteChainId] = abi.encodePacked(_remoteAddress, address(this));
                              emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress);
                          }
                          function getTrustedRemoteAddress(uint16 _remoteChainId) external view returns (bytes memory) {
                              bytes memory path = trustedRemoteLookup[_remoteChainId];
                              require(path.length != 0, "LzApp: no trusted path record");
                              return path.slice(0, path.length - 20); // the last 20 bytes should be address(this)
                          }
                          function setPrecrime(address _precrime) external onlyOwner {
                              precrime = _precrime;
                              emit SetPrecrime(_precrime);
                          }
                          function setMinDstGas(uint16 _dstChainId, uint16 _packetType, uint _minGas) external onlyOwner {
                              require(_minGas > 0, "LzApp: invalid minGas");
                              minDstGasLookup[_dstChainId][_packetType] = _minGas;
                              emit SetMinDstGas(_dstChainId, _packetType, _minGas);
                          }
                          // if the size is 0, it means default size limit
                          function setPayloadSizeLimit(uint16 _dstChainId, uint _size) external onlyOwner {
                              payloadSizeLimitLookup[_dstChainId] = _size;
                          }
                          //--------------------------- VIEW FUNCTION ----------------------------------------
                          function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) {
                              bytes memory trustedSource = trustedRemoteLookup[_srcChainId];
                              return keccak256(trustedSource) == keccak256(_srcAddress);
                          }
                          /**
                           * @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
                           */
                          uint[45] private __gap;
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.2;
                      import "./LzAppUpgradeable.sol";
                      import "../../util/ExcessivelySafeCall.sol";
                      /*
                       * the default LayerZero messaging behaviour is blocking, i.e. any failed message will block the channel
                       * this abstract class try-catch all fail messages and store locally for future retry. hence, non-blocking
                       * NOTE: if the srcAddress is not configured properly, it will still block the message pathway from (srcChainId, srcAddress)
                       */
                      abstract contract NonblockingLzAppUpgradeable is Initializable, LzAppUpgradeable {
                          using ExcessivelySafeCall for address;
                          function __NonblockingLzAppUpgradeable_init(address _endpoint) internal onlyInitializing {
                              __Ownable_init_unchained();
                              __LzAppUpgradeable_init_unchained(_endpoint);
                          }
                          function __NonblockingLzAppUpgradeable_init_unchained(address _endpoint) internal onlyInitializing {}
                          mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) public failedMessages;
                          event MessageFailed(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload, bytes _reason);
                          event RetryMessageSuccess(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _payloadHash);
                          // overriding the virtual function in LzReceiver
                          function _blockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual override {
                              (bool success, bytes memory reason) = address(this).excessivelySafeCall(gasleft(), 150, abi.encodeWithSelector(this.nonblockingLzReceive.selector, _srcChainId, _srcAddress, _nonce, _payload));
                              // try-catch all errors/exceptions
                              if (!success) {
                                  _storeFailedMessage(_srcChainId, _srcAddress, _nonce, _payload, reason);
                              }
                          }
                          function _storeFailedMessage(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload, bytes memory _reason) internal virtual {
                              failedMessages[_srcChainId][_srcAddress][_nonce] = keccak256(_payload);
                              emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload, _reason);
                          }
                          function nonblockingLzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public virtual {
                              // only internal transaction
                              require(_msgSender() == address(this), "NonblockingLzApp: caller must be LzApp");
                              _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
                          }
                          //@notice override this function
                          function _nonblockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual;
                          function retryMessage(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public payable virtual {
                              // assert there is message to retry
                              bytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce];
                              require(payloadHash != bytes32(0), "NonblockingLzApp: no stored message");
                              require(keccak256(_payload) == payloadHash, "NonblockingLzApp: invalid payload");
                              // clear the stored message
                              failedMessages[_srcChainId][_srcAddress][_nonce] = bytes32(0);
                              // execute the message. revert if it fails again
                              _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
                              emit RetryMessageSuccess(_srcChainId, _srcAddress, _nonce, payloadHash);
                          }
                          /**
                           * @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
                           */
                          uint[49] private __gap;
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.2;
                      import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
                      /**
                       * @dev Interface of the ONFT Core Upgradeable standard
                       */
                      interface IONFT721CoreUpgradeable is IERC165Upgradeable {
                          /**
                           * @dev Emitted when `_tokenIds[]` are moved from the `_sender` to (`_dstChainId`, `_toAddress`)
                           * `_nonce` is the outbound nonce from
                           */
                          event SendToChain(uint16 indexed _dstChainId, address indexed _from, bytes indexed _toAddress, uint[] _tokenIds);
                          event ReceiveFromChain(uint16 indexed _srcChainId, bytes indexed _srcAddress, address indexed _toAddress, uint[] _tokenIds);
                          /**
                           * @dev Emitted when `_payload` was received from lz, but not enough gas to deliver all tokenIds
                           */
                          event CreditStored(bytes32 _hashedPayload, bytes _payload);
                          /**
                           * @dev Emitted when `_hashedPayload` has been completely delivered
                           */
                          event CreditCleared(bytes32 _hashedPayload);
                          /**
                           * @dev send token `_tokenId` to (`_dstChainId`, `_toAddress`) from `_from`
                           * `_toAddress` can be any size depending on the `dstChainId`.
                           * `_zroPaymentAddress` set to address(0x0) if not paying in ZRO (LayerZero Token)
                           * `_adapterParams` is a flexible bytes array to indicate messaging adapter services
                           */
                          function sendFrom(address _from, uint16 _dstChainId, bytes calldata _toAddress, uint _tokenId, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
                          /**
                           * @dev send tokens `_tokenIds[]` to (`_dstChainId`, `_toAddress`) from `_from`
                           * `_toAddress` can be any size depending on the `dstChainId`.
                           * `_zroPaymentAddress` set to address(0x0) if not paying in ZRO (LayerZero Token)
                           * `_adapterParams` is a flexible bytes array to indicate messaging adapter services
                           */
                          function sendBatchFrom(address _from, uint16 _dstChainId, bytes calldata _toAddress, uint[] calldata _tokenIds, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
                          /**
                           * @dev estimate send token `_tokenId` to (`_dstChainId`, `_toAddress`)
                           * _dstChainId - L0 defined chain id to send tokens too
                           * _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain
                           * _tokenId - token Id to transfer
                           * _useZro - indicates to use zro to pay L0 fees
                           * _adapterParams - flexible bytes array to indicate messaging adapter services in L0
                           */
                          function estimateSendFee(uint16 _dstChainId, bytes calldata _toAddress, uint _tokenId, bool _useZro, bytes calldata _adapterParams) external view returns (uint nativeFee, uint zroFee);
                          /**
                           * @dev estimate send token `_tokenId` to (`_dstChainId`, `_toAddress`)
                           * _dstChainId - L0 defined chain id to send tokens too
                           * _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain
                           * _tokenIds[] - token Ids to transfer
                           * _useZro - indicates to use zro to pay L0 fees
                           * _adapterParams - flexible bytes array to indicate messaging adapter services in L0
                           */
                          function estimateSendBatchFee(uint16 _dstChainId, bytes calldata _toAddress, uint[] calldata _tokenIds, bool _useZro, bytes calldata _adapterParams) external view returns (uint nativeFee, uint zroFee);
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.4;
                      import {ERC721AUpgradeable, IERC721AUpgradeable, ERC721A__IERC721ReceiverUpgradeable} from "erc721a-upgradeable/contracts/ERC721AUpgradeable.sol";
                      import {ERC721AQueryableUpgradeable} from "erc721a-upgradeable/contracts/extensions/ERC721AQueryableUpgradeable.sol";
                      import {IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
                      import {IERC2981Upgradeable, ERC2981Upgradeable} from "@openzeppelin/contracts-upgradeable/token/common/ERC2981Upgradeable.sol";
                      import {OperatorFilterer} from "closedsea/src/OperatorFilterer.sol";
                      import {StringsUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
                      import "./IONFT721CoreUpgradeable.sol";
                      import "./ONFT721CoreUpgradeable.sol";
                      contract ONFT721AUpgradeable is
                        Initializable,
                        ONFT721CoreUpgradeable,
                        ERC721AQueryableUpgradeable,
                        ERC721A__IERC721ReceiverUpgradeable,
                        ERC2981Upgradeable,
                        OperatorFilterer
                      {
                        using StringsUpgradeable for uint;
                        /// @notice Base uri
                        string public baseURI;
                        /// @notice Operator filter toggle switch
                        bool private operatorFilteringEnabled;
                        /// @notice Delegation registry
                        address public delegationRegistryAddress;
                        function __ONFT721AUpgradeable_init(
                          string memory _name,
                          string memory _symbol,
                          string memory _baseURI,
                          uint _minGasToTransferAndStore,
                          address _lzEndpoint
                        ) internal initializerERC721A onlyInitializing {
                          __ERC721A_init_unchained(_name, _symbol);
                          __ERC2981_init_unchained();
                          __ONFT721CoreUpgradeable_init(_minGasToTransferAndStore, _lzEndpoint);
                          baseURI = _baseURI;
                          // Setup filter registry
                          _registerForOperatorFiltering();
                          operatorFilteringEnabled = true;
                          // Setup royalties to 5% (default denominator is 10000)
                          _setDefaultRoyalty(_msgSender(), 500);
                        }
                        function __ONFT721AUpgradeable_init_unchained() internal onlyInitializing {}
                        function _startTokenId() internal view virtual override returns (uint) {
                          return 1;
                        }
                        function supportsInterface(bytes4 interfaceId)
                          public
                          view
                          virtual
                          override(
                            ONFT721CoreUpgradeable,
                            IERC721AUpgradeable,
                            ERC721AUpgradeable,
                            ERC2981Upgradeable
                          )
                          returns (bool)
                        {
                          return
                            interfaceId == type(IONFT721CoreUpgradeable).interfaceId ||
                            ERC721AUpgradeable.supportsInterface(interfaceId) ||
                            ERC2981Upgradeable.supportsInterface(interfaceId);
                        }
                        function _debitFrom(
                          address _from,
                          uint16,
                          bytes memory,
                          uint _tokenId
                        ) internal virtual override(ONFT721CoreUpgradeable) {
                          safeTransferFrom(_from, address(this), _tokenId);
                        }
                        function _creditTo(
                          uint16,
                          address _toAddress,
                          uint _tokenId
                        ) internal virtual override(ONFT721CoreUpgradeable) {
                          require(
                            _exists(_tokenId) && ERC721AUpgradeable.ownerOf(_tokenId) == address(this)
                          );
                          safeTransferFrom(address(this), _toAddress, _tokenId);
                        }
                        function onERC721Received(
                          address,
                          address,
                          uint,
                          bytes memory
                        ) public virtual override returns (bytes4) {
                          return ERC721A__IERC721ReceiverUpgradeable.onERC721Received.selector;
                        }
                        function setApprovalForAll(address operator, bool approved)
                          public
                          override(IERC721AUpgradeable, ERC721AUpgradeable)
                          onlyAllowedOperatorApproval(operator)
                        {
                          super.setApprovalForAll(operator, approved);
                        }
                        function approve(address operator, uint tokenId)
                          public
                          payable
                          override(IERC721AUpgradeable, ERC721AUpgradeable)
                          onlyAllowedOperatorApproval(operator)
                        {
                          super.approve(operator, tokenId);
                        }
                        function transferFrom(
                          address from,
                          address to,
                          uint tokenId
                        )
                          public
                          payable
                          override(IERC721AUpgradeable, ERC721AUpgradeable)
                          onlyAllowedOperator(from)
                        {
                          super.transferFrom(from, to, tokenId);
                        }
                        function safeTransferFrom(
                          address from,
                          address to,
                          uint tokenId
                        )
                          public
                          payable
                          override(IERC721AUpgradeable, ERC721AUpgradeable)
                          onlyAllowedOperator(from)
                        {
                          super.safeTransferFrom(from, to, tokenId);
                        }
                        function safeTransferFrom(
                          address from,
                          address to,
                          uint tokenId,
                          bytes memory data
                        )
                          public
                          payable
                          override(IERC721AUpgradeable, ERC721AUpgradeable)
                          onlyAllowedOperator(from)
                        {
                          super.safeTransferFrom(from, to, tokenId, data);
                        }
                        /**
                         * @notice Token uri
                         * @param tokenId The token id
                         */
                        function tokenURI(uint tokenId)
                          public
                          view
                          virtual
                          override(IERC721AUpgradeable, ERC721AUpgradeable)
                          returns (string memory)
                        {
                          require(_exists(tokenId), "!exists");
                          return
                            bytes(baseURI).length > 0
                              ? string(abi.encodePacked(baseURI, tokenId.toString()))
                              : "";
                        }
                        /**
                         * @notice Sets the base uri for the token metadata
                         * @param _baseURI The base uri
                         */
                        function setBaseURI(string memory _baseURI) external onlyOwner {
                          baseURI = _baseURI;
                        }
                        /**
                         * @notice Set default royalty
                         * @param receiver The royalty receiver address
                         * @param feeNumerator A number for 10k basis
                         */
                        function setDefaultRoyalty(address receiver, uint96 feeNumerator)
                          external
                          onlyOwner
                        {
                          _setDefaultRoyalty(receiver, feeNumerator);
                        }
                        /**
                         * @notice Sets whether the operator filter is enabled or disabled
                         * @param operatorFilteringEnabled_ A boolean value for the operator filter
                         */
                        function setOperatorFilteringEnabled(bool operatorFilteringEnabled_)
                          public
                          onlyOwner
                        {
                          operatorFilteringEnabled = operatorFilteringEnabled_;
                        }
                        function _operatorFilteringEnabled() internal view override returns (bool) {
                          return operatorFilteringEnabled;
                        }
                        function _isPriorityOperator(address operator)
                          internal
                          pure
                          override
                          returns (bool)
                        {
                          // OpenSea Seaport Conduit:
                          // https://etherscan.io/address/0x1E0049783F008A0085193E00003D00cd54003c71
                          return operator == address(0x1E0049783F008A0085193E00003D00cd54003c71);
                        }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.2;
                      import "./IONFT721CoreUpgradeable.sol";
                      import "../../../lzApp/NonblockingLzAppUpgradeable.sol";
                      import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
                      abstract contract ONFT721CoreUpgradeable is
                        Initializable,
                        NonblockingLzAppUpgradeable,
                        ERC165Upgradeable,
                        IONFT721CoreUpgradeable
                      {
                        uint16 public constant FUNCTION_TYPE_SEND = 1;
                        struct StoredCredit {
                          uint16 srcChainId;
                          address toAddress;
                          uint index; // which index of the tokenIds remain
                          bool creditsRemain;
                        }
                        uint public minGasToTransferAndStore; // min amount of gas required to transfer, and also store the payload
                        mapping(uint16 => uint) public dstChainIdToBatchLimit;
                        mapping(uint16 => uint) public dstChainIdToTransferGas; // per transfer amount of gas required to mint/transfer on the dst
                        mapping(bytes32 => StoredCredit) public storedCredits;
                        function __ONFT721CoreUpgradeable_init(
                          uint _minGasToTransferAndStore,
                          address _lzEndpoint
                        ) internal onlyInitializing {
                          __Ownable_init_unchained();
                          __LzAppUpgradeable_init_unchained(_lzEndpoint);
                          __ONFT721CoreUpgradeable_init_unchained(_minGasToTransferAndStore);
                        }
                        function __ONFT721CoreUpgradeable_init_unchained(
                          uint _minGasToTransferAndStore
                        ) internal onlyInitializing {
                          require(
                            _minGasToTransferAndStore > 0,
                            "ONFT721: minGasToTransferAndStore must be > 0"
                          );
                          minGasToTransferAndStore = _minGasToTransferAndStore;
                        }
                        function supportsInterface(bytes4 interfaceId)
                          public
                          view
                          virtual
                          override(ERC165Upgradeable, IERC165Upgradeable)
                          returns (bool)
                        {
                          return
                            interfaceId == type(IONFT721CoreUpgradeable).interfaceId ||
                            super.supportsInterface(interfaceId);
                        }
                        function estimateSendFee(
                          uint16 _dstChainId,
                          bytes memory _toAddress,
                          uint _tokenId,
                          bool _useZro,
                          bytes memory _adapterParams
                        ) public view virtual override returns (uint nativeFee, uint zroFee) {
                          return
                            estimateSendBatchFee(
                              _dstChainId,
                              _toAddress,
                              _toSingletonArray(_tokenId),
                              _useZro,
                              _adapterParams
                            );
                        }
                        function estimateSendBatchFee(
                          uint16 _dstChainId,
                          bytes memory _toAddress,
                          uint[] memory _tokenIds,
                          bool _useZro,
                          bytes memory _adapterParams
                        ) public view virtual override returns (uint nativeFee, uint zroFee) {
                          bytes memory payload = abi.encode(_toAddress, _tokenIds);
                          return
                            lzEndpoint.estimateFees(
                              _dstChainId,
                              address(this),
                              payload,
                              _useZro,
                              _adapterParams
                            );
                        }
                        function sendFrom(
                          address _from,
                          uint16 _dstChainId,
                          bytes memory _toAddress,
                          uint _tokenId,
                          address payable _refundAddress,
                          address _zroPaymentAddress,
                          bytes memory _adapterParams
                        ) public payable virtual override {
                          _send(
                            _from,
                            _dstChainId,
                            _toAddress,
                            _toSingletonArray(_tokenId),
                            _refundAddress,
                            _zroPaymentAddress,
                            _adapterParams
                          );
                        }
                        function sendBatchFrom(
                          address _from,
                          uint16 _dstChainId,
                          bytes memory _toAddress,
                          uint[] memory _tokenIds,
                          address payable _refundAddress,
                          address _zroPaymentAddress,
                          bytes memory _adapterParams
                        ) public payable virtual override {
                          _send(
                            _from,
                            _dstChainId,
                            _toAddress,
                            _tokenIds,
                            _refundAddress,
                            _zroPaymentAddress,
                            _adapterParams
                          );
                        }
                        function _send(
                          address _from,
                          uint16 _dstChainId,
                          bytes memory _toAddress,
                          uint[] memory _tokenIds,
                          address payable _refundAddress,
                          address _zroPaymentAddress,
                          bytes memory _adapterParams
                        ) internal virtual {
                          // allow 1 by default
                          require(_tokenIds.length > 0, "LzApp: tokenIds[] is empty");
                          require(
                            _tokenIds.length == 1 ||
                              _tokenIds.length <= dstChainIdToBatchLimit[_dstChainId],
                            "ONFT721: batch size exceeds dst batch limit"
                          );
                          for (uint i = 0; i < _tokenIds.length; i++) {
                            _debitFrom(_from, _dstChainId, _toAddress, _tokenIds[i]);
                          }
                          bytes memory payload = abi.encode(_toAddress, _tokenIds);
                          _checkGasLimit(
                            _dstChainId,
                            FUNCTION_TYPE_SEND,
                            _adapterParams,
                            dstChainIdToTransferGas[_dstChainId] * _tokenIds.length
                          );
                          _lzSend(
                            _dstChainId,
                            payload,
                            _refundAddress,
                            _zroPaymentAddress,
                            _adapterParams,
                            msg.value
                          );
                          emit SendToChain(_dstChainId, _from, _toAddress, _tokenIds);
                        }
                        function _nonblockingLzReceive(
                          uint16 _srcChainId,
                          bytes memory _srcAddress,
                          uint64, /*_nonce*/
                          bytes memory _payload
                        ) internal virtual override {
                          // decode and load the toAddress
                          (bytes memory toAddressBytes, uint[] memory tokenIds) = abi.decode(
                            _payload,
                            (bytes, uint[])
                          );
                          address toAddress;
                          assembly {
                            toAddress := mload(add(toAddressBytes, 20))
                          }
                          uint nextIndex = _creditTill(_srcChainId, toAddress, 0, tokenIds);
                          if (nextIndex < tokenIds.length) {
                            // not enough gas to complete transfers, store to be cleared in another tx
                            bytes32 hashedPayload = keccak256(_payload);
                            storedCredits[hashedPayload] = StoredCredit(
                              _srcChainId,
                              toAddress,
                              nextIndex,
                              true
                            );
                            emit CreditStored(hashedPayload, _payload);
                          }
                          emit ReceiveFromChain(_srcChainId, _srcAddress, toAddress, tokenIds);
                        }
                        // Public function for anyone to clear and deliver the remaining batch sent tokenIds
                        function clearCredits(bytes memory _payload) external {
                          bytes32 hashedPayload = keccak256(_payload);
                          require(
                            storedCredits[hashedPayload].creditsRemain,
                            "ONFT721: no credits stored"
                          );
                          (, uint[] memory tokenIds) = abi.decode(_payload, (bytes, uint[]));
                          uint nextIndex = _creditTill(
                            storedCredits[hashedPayload].srcChainId,
                            storedCredits[hashedPayload].toAddress,
                            storedCredits[hashedPayload].index,
                            tokenIds
                          );
                          require(
                            nextIndex > storedCredits[hashedPayload].index,
                            "ONFT721: not enough gas to process credit transfer"
                          );
                          if (nextIndex == tokenIds.length) {
                            // cleared the credits, delete the element
                            delete storedCredits[hashedPayload];
                            emit CreditCleared(hashedPayload);
                          } else {
                            // store the next index to mint
                            storedCredits[hashedPayload] = StoredCredit(
                              storedCredits[hashedPayload].srcChainId,
                              storedCredits[hashedPayload].toAddress,
                              nextIndex,
                              true
                            );
                          }
                        }
                        // When a srcChain has the ability to transfer more chainIds in a single tx than the dst can do.
                        // Needs the ability to iterate and stop if the minGasToTransferAndStore is not met
                        function _creditTill(
                          uint16 _srcChainId,
                          address _toAddress,
                          uint _startIndex,
                          uint[] memory _tokenIds
                        ) internal returns (uint) {
                          uint i = _startIndex;
                          while (i < _tokenIds.length) {
                            // if not enough gas to process, store this index for next loop
                            if (gasleft() < minGasToTransferAndStore) break;
                            _creditTo(_srcChainId, _toAddress, _tokenIds[i]);
                            i++;
                          }
                          // indicates the next index to send of tokenIds,
                          // if i == tokenIds.length, we are finished
                          return i;
                        }
                        function setMinGasToTransferAndStore(uint _minGasToTransferAndStore)
                          external
                          onlyOwner
                        {
                          require(
                            _minGasToTransferAndStore > 0,
                            "ONFT721: minGasToTransferAndStore must be > 0"
                          );
                          minGasToTransferAndStore = _minGasToTransferAndStore;
                        }
                        // ensures enough gas in adapter params to handle batch transfer gas amounts on the dst
                        function setDstChainIdToTransferGas(
                          uint16 _dstChainId,
                          uint _dstChainIdToTransferGas
                        ) external onlyOwner {
                          require(
                            _dstChainIdToTransferGas > 0,
                            "ONFT721: dstChainIdToTransferGas must be > 0"
                          );
                          dstChainIdToTransferGas[_dstChainId] = _dstChainIdToTransferGas;
                        }
                        // limit on src the amount of tokens to batch send
                        function setDstChainIdToBatchLimit(
                          uint16 _dstChainId,
                          uint _dstChainIdToBatchLimit
                        ) external onlyOwner {
                          require(
                            _dstChainIdToBatchLimit > 0,
                            "ONFT721: dstChainIdToBatchLimit must be > 0"
                          );
                          dstChainIdToBatchLimit[_dstChainId] = _dstChainIdToBatchLimit;
                        }
                        function _debitFrom(
                          address _from,
                          uint16 _dstChainId,
                          bytes memory _toAddress,
                          uint _tokenId
                        ) internal virtual;
                        function _creditTo(
                          uint16 _srcChainId,
                          address _toAddress,
                          uint _tokenId
                        ) internal virtual;
                        function _toSingletonArray(uint element)
                          internal
                          pure
                          returns (uint[] memory)
                        {
                          uint[] memory array = new uint[](1);
                          array[0] = element;
                          return array;
                        }
                        /**
                         * @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
                         */
                        uint[46] private __gap;
                      }
                      // SPDX-License-Identifier: CC0-1.0
                      pragma solidity ^0.8.17;
                      /**
                       * @title An immutable registry contract to be deployed as a standalone primitive
                       * @dev See EIP-5639, new project launches can read previous cold wallet -> hot wallet delegations
                       *      from here and integrate those permissions into their flow
                       */
                      interface IDelegationRegistry {
                        /// @notice Delegation type
                        enum DelegationType {
                          NONE,
                          ALL,
                          CONTRACT,
                          TOKEN
                        }
                        /// @notice Info about a single delegation, used for onchain enumeration
                        struct DelegationInfo {
                          DelegationType type_;
                          address vault;
                          address delegate;
                          address contract_;
                          uint tokenId;
                        }
                        /// @notice Info about a single contract-level delegation
                        struct ContractDelegation {
                          address contract_;
                          address delegate;
                        }
                        /// @notice Info about a single token-level delegation
                        struct TokenDelegation {
                          address contract_;
                          uint tokenId;
                          address delegate;
                        }
                        /// @notice Emitted when a user delegates their entire wallet
                        event DelegateForAll(address vault, address delegate, bool value);
                        /// @notice Emitted when a user delegates a specific contract
                        event DelegateForContract(
                          address vault,
                          address delegate,
                          address contract_,
                          bool value
                        );
                        /// @notice Emitted when a user delegates a specific token
                        event DelegateForToken(
                          address vault,
                          address delegate,
                          address contract_,
                          uint tokenId,
                          bool value
                        );
                        /// @notice Emitted when a user revokes all delegations
                        event RevokeAllDelegates(address vault);
                        /// @notice Emitted when a user revoes all delegations for a given delegate
                        event RevokeDelegate(address vault, address delegate);
                        /**
                         * -----------  WRITE -----------
                         */
                        /**
                         * @notice Allow the delegate to act on your behalf for all contracts
                         * @param delegate The hotwallet to act on your behalf
                         * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
                         */
                        function delegateForAll(address delegate, bool value) external;
                        /**
                         * @notice Allow the delegate to act on your behalf for a specific contract
                         * @param delegate The hotwallet to act on your behalf
                         * @param contract_ The address for the contract you're delegating
                         * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
                         */
                        function delegateForContract(
                          address delegate,
                          address contract_,
                          bool value
                        ) external;
                        /**
                         * @notice Allow the delegate to act on your behalf for a specific token
                         * @param delegate The hotwallet to act on your behalf
                         * @param contract_ The address for the contract you're delegating
                         * @param tokenId The token id for the token you're delegating
                         * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
                         */
                        function delegateForToken(
                          address delegate,
                          address contract_,
                          uint tokenId,
                          bool value
                        ) external;
                        /**
                         * @notice Revoke all delegates
                         */
                        function revokeAllDelegates() external;
                        /**
                         * @notice Revoke a specific delegate for all their permissions
                         * @param delegate The hotwallet to revoke
                         */
                        function revokeDelegate(address delegate) external;
                        /**
                         * @notice Remove yourself as a delegate for a specific vault
                         * @param vault The vault which delegated to the msg.sender, and should be removed
                         */
                        function revokeSelf(address vault) external;
                        /**
                         * -----------  READ -----------
                         */
                        /**
                         * @notice Returns all active delegations a given delegate is able to claim on behalf of
                         * @param delegate The delegate that you would like to retrieve delegations for
                         * @return info Array of DelegationInfo structs
                         */
                        function getDelegationsByDelegate(address delegate)
                          external
                          view
                          returns (DelegationInfo[] memory);
                        /**
                         * @notice Returns an array of wallet-level delegates for a given vault
                         * @param vault The cold wallet who issued the delegation
                         * @return addresses Array of wallet-level delegates for a given vault
                         */
                        function getDelegatesForAll(address vault)
                          external
                          view
                          returns (address[] memory);
                        /**
                         * @notice Returns an array of contract-level delegates for a given vault and contract
                         * @param vault The cold wallet who issued the delegation
                         * @param contract_ The address for the contract you're delegating
                         * @return addresses Array of contract-level delegates for a given vault and contract
                         */
                        function getDelegatesForContract(address vault, address contract_)
                          external
                          view
                          returns (address[] memory);
                        /**
                         * @notice Returns an array of contract-level delegates for a given vault's token
                         * @param vault The cold wallet who issued the delegation
                         * @param contract_ The address for the contract holding the token
                         * @param tokenId The token id for the token you're delegating
                         * @return addresses Array of contract-level delegates for a given vault's token
                         */
                        function getDelegatesForToken(
                          address vault,
                          address contract_,
                          uint tokenId
                        ) external view returns (address[] memory);
                        /**
                         * @notice Returns all contract-level delegations for a given vault
                         * @param vault The cold wallet who issued the delegations
                         * @return delegations Array of ContractDelegation structs
                         */
                        function getContractLevelDelegations(address vault)
                          external
                          view
                          returns (ContractDelegation[] memory delegations);
                        /**
                         * @notice Returns all token-level delegations for a given vault
                         * @param vault The cold wallet who issued the delegations
                         * @return delegations Array of TokenDelegation structs
                         */
                        function getTokenLevelDelegations(address vault)
                          external
                          view
                          returns (TokenDelegation[] memory delegations);
                        /**
                         * @notice Returns true if the address is delegated to act on the entire vault
                         * @param delegate The hotwallet to act on your behalf
                         * @param vault The cold wallet who issued the delegation
                         */
                        function checkDelegateForAll(address delegate, address vault)
                          external
                          view
                          returns (bool);
                        /**
                         * @notice Returns true if the address is delegated to act on your behalf for a token contract or an entire vault
                         * @param delegate The hotwallet to act on your behalf
                         * @param contract_ The address for the contract you're delegating
                         * @param vault The cold wallet who issued the delegation
                         */
                        function checkDelegateForContract(
                          address delegate,
                          address vault,
                          address contract_
                        ) external view returns (bool);
                        /**
                         * @notice Returns true if the address is delegated to act on your behalf for a specific token, the token's contract or an entire vault
                         * @param delegate The hotwallet to act on your behalf
                         * @param contract_ The address for the contract you're delegating
                         * @param tokenId The token id for the token you're delegating
                         * @param vault The cold wallet who issued the delegation
                         */
                        function checkDelegateForToken(
                          address delegate,
                          address vault,
                          address contract_,
                          uint tokenId
                        ) external view returns (bool);
                      }
                      // SPDX-License-Identifier: Unlicense
                      /*
                       * @title Solidity Bytes Arrays Utils
                       * @author Gonçalo Sá <goncalo.sa@consensys.net>
                       *
                       * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
                       *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
                       */
                      pragma solidity >=0.8.0 <0.9.0;
                      library BytesLib {
                          function concat(
                              bytes memory _preBytes,
                              bytes memory _postBytes
                          )
                          internal
                          pure
                          returns (bytes memory)
                          {
                              bytes memory tempBytes;
                              assembly {
                              // Get a location of some free memory and store it in tempBytes as
                              // Solidity does for memory variables.
                                  tempBytes := mload(0x40)
                              // Store the length of the first bytes array at the beginning of
                              // the memory for tempBytes.
                                  let length := mload(_preBytes)
                                  mstore(tempBytes, length)
                              // Maintain a memory counter for the current write location in the
                              // temp bytes array by adding the 32 bytes for the array length to
                              // the starting location.
                                  let mc := add(tempBytes, 0x20)
                              // Stop copying when the memory counter reaches the length of the
                              // first bytes array.
                                  let end := add(mc, length)
                                  for {
                                  // Initialize a copy counter to the start of the _preBytes data,
                                  // 32 bytes into its memory.
                                      let cc := add(_preBytes, 0x20)
                                  } lt(mc, end) {
                                  // Increase both counters by 32 bytes each iteration.
                                      mc := add(mc, 0x20)
                                      cc := add(cc, 0x20)
                                  } {
                                  // Write the _preBytes data into the tempBytes memory 32 bytes
                                  // at a time.
                                      mstore(mc, mload(cc))
                                  }
                              // Add the length of _postBytes to the current length of tempBytes
                              // and store it as the new length in the first 32 bytes of the
                              // tempBytes memory.
                                  length := mload(_postBytes)
                                  mstore(tempBytes, add(length, mload(tempBytes)))
                              // Move the memory counter back from a multiple of 0x20 to the
                              // actual end of the _preBytes data.
                                  mc := end
                              // Stop copying when the memory counter reaches the new combined
                              // length of the arrays.
                                  end := add(mc, length)
                                  for {
                                      let cc := add(_postBytes, 0x20)
                                  } lt(mc, end) {
                                      mc := add(mc, 0x20)
                                      cc := add(cc, 0x20)
                                  } {
                                      mstore(mc, mload(cc))
                                  }
                              // Update the free-memory pointer by padding our last write location
                              // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
                              // next 32 byte block, then round down to the nearest multiple of
                              // 32. If the sum of the length of the two arrays is zero then add
                              // one before rounding down to leave a blank 32 bytes (the length block with 0).
                                  mstore(0x40, and(
                                  add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                                  not(31) // Round down to the nearest 32 bytes.
                                  ))
                              }
                              return tempBytes;
                          }
                          function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
                              assembly {
                              // Read the first 32 bytes of _preBytes storage, which is the length
                              // of the array. (We don't need to use the offset into the slot
                              // because arrays use the entire slot.)
                                  let fslot := sload(_preBytes.slot)
                              // Arrays of 31 bytes or less have an even value in their slot,
                              // while longer arrays have an odd value. The actual length is
                              // the slot divided by two for odd values, and the lowest order
                              // byte divided by two for even values.
                              // If the slot is even, bitwise and the slot with 255 and divide by
                              // two to get the length. If the slot is odd, bitwise and the slot
                              // with -1 and divide by two.
                                  let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                                  let mlength := mload(_postBytes)
                                  let newlength := add(slength, mlength)
                              // slength can contain both the length and contents of the array
                              // if length < 32 bytes so let's prepare for that
                              // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                                  switch add(lt(slength, 32), lt(newlength, 32))
                                  case 2 {
                                  // Since the new array still fits in the slot, we just need to
                                  // update the contents of the slot.
                                  // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                                      sstore(
                                      _preBytes.slot,
                                      // all the modifications to the slot are inside this
                                      // next block
                                      add(
                                      // we can just add to the slot contents because the
                                      // bytes we want to change are the LSBs
                                      fslot,
                                      add(
                                      mul(
                                      div(
                                      // load the bytes from memory
                                      mload(add(_postBytes, 0x20)),
                                      // zero all bytes to the right
                                      exp(0x100, sub(32, mlength))
                                      ),
                                      // and now shift left the number of bytes to
                                      // leave space for the length in the slot
                                      exp(0x100, sub(32, newlength))
                                      ),
                                      // increase length by the double of the memory
                                      // bytes length
                                      mul(mlength, 2)
                                      )
                                      )
                                      )
                                  }
                                  case 1 {
                                  // The stored value fits in the slot, but the combined value
                                  // will exceed it.
                                  // get the keccak hash to get the contents of the array
                                      mstore(0x0, _preBytes.slot)
                                      let sc := add(keccak256(0x0, 0x20), div(slength, 32))
                                  // save new length
                                      sstore(_preBytes.slot, add(mul(newlength, 2), 1))
                                  // The contents of the _postBytes array start 32 bytes into
                                  // the structure. Our first read should obtain the `submod`
                                  // bytes that can fit into the unused space in the last word
                                  // of the stored array. To get this, we read 32 bytes starting
                                  // from `submod`, so the data we read overlaps with the array
                                  // contents by `submod` bytes. Masking the lowest-order
                                  // `submod` bytes allows us to add that value directly to the
                                  // stored value.
                                      let submod := sub(32, slength)
                                      let mc := add(_postBytes, submod)
                                      let end := add(_postBytes, mlength)
                                      let mask := sub(exp(0x100, submod), 1)
                                      sstore(
                                      sc,
                                      add(
                                      and(
                                      fslot,
                                      0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                                      ),
                                      and(mload(mc), mask)
                                      )
                                      )
                                      for {
                                          mc := add(mc, 0x20)
                                          sc := add(sc, 1)
                                      } lt(mc, end) {
                                          sc := add(sc, 1)
                                          mc := add(mc, 0x20)
                                      } {
                                          sstore(sc, mload(mc))
                                      }
                                      mask := exp(0x100, sub(mc, end))
                                      sstore(sc, mul(div(mload(mc), mask), mask))
                                  }
                                  default {
                                  // get the keccak hash to get the contents of the array
                                      mstore(0x0, _preBytes.slot)
                                  // Start copying to the last used word of the stored array.
                                      let sc := add(keccak256(0x0, 0x20), div(slength, 32))
                                  // save new length
                                      sstore(_preBytes.slot, add(mul(newlength, 2), 1))
                                  // Copy over the first `submod` bytes of the new data as in
                                  // case 1 above.
                                      let slengthmod := mod(slength, 32)
                                      let mlengthmod := mod(mlength, 32)
                                      let submod := sub(32, slengthmod)
                                      let mc := add(_postBytes, submod)
                                      let end := add(_postBytes, mlength)
                                      let mask := sub(exp(0x100, submod), 1)
                                      sstore(sc, add(sload(sc), and(mload(mc), mask)))
                                      for {
                                          sc := add(sc, 1)
                                          mc := add(mc, 0x20)
                                      } lt(mc, end) {
                                          sc := add(sc, 1)
                                          mc := add(mc, 0x20)
                                      } {
                                          sstore(sc, mload(mc))
                                      }
                                      mask := exp(0x100, sub(mc, end))
                                      sstore(sc, mul(div(mload(mc), mask), mask))
                                  }
                              }
                          }
                          function slice(
                              bytes memory _bytes,
                              uint256 _start,
                              uint256 _length
                          )
                          internal
                          pure
                          returns (bytes memory)
                          {
                              require(_length + 31 >= _length, "slice_overflow");
                              require(_bytes.length >= _start + _length, "slice_outOfBounds");
                              bytes memory tempBytes;
                              assembly {
                                  switch iszero(_length)
                                  case 0 {
                                  // Get a location of some free memory and store it in tempBytes as
                                  // Solidity does for memory variables.
                                      tempBytes := mload(0x40)
                                  // The first word of the slice result is potentially a partial
                                  // word read from the original array. To read it, we calculate
                                  // the length of that partial word and start copying that many
                                  // bytes into the array. The first word we copy will start with
                                  // data we don't care about, but the last `lengthmod` bytes will
                                  // land at the beginning of the contents of the new array. When
                                  // we're done copying, we overwrite the full first word with
                                  // the actual length of the slice.
                                      let lengthmod := and(_length, 31)
                                  // The multiplication in the next line is necessary
                                  // because when slicing multiples of 32 bytes (lengthmod == 0)
                                  // the following copy loop was copying the origin's length
                                  // and then ending prematurely not copying everything it should.
                                      let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                                      let end := add(mc, _length)
                                      for {
                                      // The multiplication in the next line has the same exact purpose
                                      // as the one above.
                                          let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                                      } lt(mc, end) {
                                          mc := add(mc, 0x20)
                                          cc := add(cc, 0x20)
                                      } {
                                          mstore(mc, mload(cc))
                                      }
                                      mstore(tempBytes, _length)
                                  //update free-memory pointer
                                  //allocating the array padded to 32 bytes like the compiler does now
                                      mstore(0x40, and(add(mc, 31), not(31)))
                                  }
                                  //if we want a zero-length slice let's just return a zero-length array
                                  default {
                                      tempBytes := mload(0x40)
                                  //zero out the 32 bytes slice we are about to return
                                  //we need to do it because Solidity does not garbage collect
                                      mstore(tempBytes, 0)
                                      mstore(0x40, add(tempBytes, 0x20))
                                  }
                              }
                              return tempBytes;
                          }
                          function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
                              require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
                              address tempAddress;
                              assembly {
                                  tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
                              }
                              return tempAddress;
                          }
                          function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
                              require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
                              uint8 tempUint;
                              assembly {
                                  tempUint := mload(add(add(_bytes, 0x1), _start))
                              }
                              return tempUint;
                          }
                          function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
                              require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
                              uint16 tempUint;
                              assembly {
                                  tempUint := mload(add(add(_bytes, 0x2), _start))
                              }
                              return tempUint;
                          }
                          function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
                              require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
                              uint32 tempUint;
                              assembly {
                                  tempUint := mload(add(add(_bytes, 0x4), _start))
                              }
                              return tempUint;
                          }
                          function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
                              require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
                              uint64 tempUint;
                              assembly {
                                  tempUint := mload(add(add(_bytes, 0x8), _start))
                              }
                              return tempUint;
                          }
                          function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
                              require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
                              uint96 tempUint;
                              assembly {
                                  tempUint := mload(add(add(_bytes, 0xc), _start))
                              }
                              return tempUint;
                          }
                          function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
                              require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
                              uint128 tempUint;
                              assembly {
                                  tempUint := mload(add(add(_bytes, 0x10), _start))
                              }
                              return tempUint;
                          }
                          function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
                              require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
                              uint256 tempUint;
                              assembly {
                                  tempUint := mload(add(add(_bytes, 0x20), _start))
                              }
                              return tempUint;
                          }
                          function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
                              require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
                              bytes32 tempBytes32;
                              assembly {
                                  tempBytes32 := mload(add(add(_bytes, 0x20), _start))
                              }
                              return tempBytes32;
                          }
                          function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
                              bool success = true;
                              assembly {
                                  let length := mload(_preBytes)
                              // if lengths don't match the arrays are not equal
                                  switch eq(length, mload(_postBytes))
                                  case 1 {
                                  // cb is a circuit breaker in the for loop since there's
                                  //  no said feature for inline assembly loops
                                  // cb = 1 - don't breaker
                                  // cb = 0 - break
                                      let cb := 1
                                      let mc := add(_preBytes, 0x20)
                                      let end := add(mc, length)
                                      for {
                                          let cc := add(_postBytes, 0x20)
                                      // the next line is the loop condition:
                                      // while(uint256(mc < end) + cb == 2)
                                      } eq(add(lt(mc, end), cb), 2) {
                                          mc := add(mc, 0x20)
                                          cc := add(cc, 0x20)
                                      } {
                                      // if any of these checks fails then arrays are not equal
                                          if iszero(eq(mload(mc), mload(cc))) {
                                          // unsuccess:
                                              success := 0
                                              cb := 0
                                          }
                                      }
                                  }
                                  default {
                                  // unsuccess:
                                      success := 0
                                  }
                              }
                              return success;
                          }
                          function equalStorage(
                              bytes storage _preBytes,
                              bytes memory _postBytes
                          )
                          internal
                          view
                          returns (bool)
                          {
                              bool success = true;
                              assembly {
                              // we know _preBytes_offset is 0
                                  let fslot := sload(_preBytes.slot)
                              // Decode the length of the stored array like in concatStorage().
                                  let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                                  let mlength := mload(_postBytes)
                              // if lengths don't match the arrays are not equal
                                  switch eq(slength, mlength)
                                  case 1 {
                                  // slength can contain both the length and contents of the array
                                  // if length < 32 bytes so let's prepare for that
                                  // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                                      if iszero(iszero(slength)) {
                                          switch lt(slength, 32)
                                          case 1 {
                                          // blank the last byte which is the length
                                              fslot := mul(div(fslot, 0x100), 0x100)
                                              if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                                              // unsuccess:
                                                  success := 0
                                              }
                                          }
                                          default {
                                          // cb is a circuit breaker in the for loop since there's
                                          //  no said feature for inline assembly loops
                                          // cb = 1 - don't breaker
                                          // cb = 0 - break
                                              let cb := 1
                                          // get the keccak hash to get the contents of the array
                                              mstore(0x0, _preBytes.slot)
                                              let sc := keccak256(0x0, 0x20)
                                              let mc := add(_postBytes, 0x20)
                                              let end := add(mc, mlength)
                                          // the next line is the loop condition:
                                          // while(uint256(mc < end) + cb == 2)
                                              for {} eq(add(lt(mc, end), cb), 2) {
                                                  sc := add(sc, 1)
                                                  mc := add(mc, 0x20)
                                              } {
                                                  if iszero(eq(sload(sc), mload(mc))) {
                                                  // unsuccess:
                                                      success := 0
                                                      cb := 0
                                                  }
                                              }
                                          }
                                      }
                                  }
                                  default {
                                  // unsuccess:
                                      success := 0
                                  }
                              }
                              return success;
                          }
                      }
                      // SPDX-License-Identifier: MIT OR Apache-2.0
                      pragma solidity >=0.7.6;
                      library ExcessivelySafeCall {
                          uint256 constant LOW_28_MASK =
                          0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
                          /// @notice Use when you _really_ really _really_ don't trust the called
                          /// contract. This prevents the called contract from causing reversion of
                          /// the caller in as many ways as we can.
                          /// @dev The main difference between this and a solidity low-level call is
                          /// that we limit the number of bytes that the callee can cause to be
                          /// copied to caller memory. This prevents stupid things like malicious
                          /// contracts returning 10,000,000 bytes causing a local OOG when copying
                          /// to memory.
                          /// @param _target The address to call
                          /// @param _gas The amount of gas to forward to the remote contract
                          /// @param _maxCopy The maximum number of bytes of returndata to copy
                          /// to memory.
                          /// @param _calldata The data to send to the remote contract
                          /// @return success and returndata, as `.call()`. Returndata is capped to
                          /// `_maxCopy` bytes.
                          function excessivelySafeCall(
                              address _target,
                              uint256 _gas,
                              uint16 _maxCopy,
                              bytes memory _calldata
                          ) internal returns (bool, bytes memory) {
                              // set up for assembly call
                              uint256 _toCopy;
                              bool _success;
                              bytes memory _returnData = new bytes(_maxCopy);
                              // dispatch message to recipient
                              // by assembly calling "handle" function
                              // we call via assembly to avoid memcopying a very large returndata
                              // returned by a malicious contract
                              assembly {
                                  _success := call(
                                  _gas, // gas
                                  _target, // recipient
                                  0, // ether value
                                  add(_calldata, 0x20), // inloc
                                  mload(_calldata), // inlen
                                  0, // outloc
                                  0 // outlen
                                  )
                              // limit our copy to 256 bytes
                                  _toCopy := returndatasize()
                                  if gt(_toCopy, _maxCopy) {
                                      _toCopy := _maxCopy
                                  }
                              // Store the length of the copied bytes
                                  mstore(_returnData, _toCopy)
                              // copy the bytes from returndata[0:_toCopy]
                                  returndatacopy(add(_returnData, 0x20), 0, _toCopy)
                              }
                              return (_success, _returnData);
                          }
                          /// @notice Use when you _really_ really _really_ don't trust the called
                          /// contract. This prevents the called contract from causing reversion of
                          /// the caller in as many ways as we can.
                          /// @dev The main difference between this and a solidity low-level call is
                          /// that we limit the number of bytes that the callee can cause to be
                          /// copied to caller memory. This prevents stupid things like malicious
                          /// contracts returning 10,000,000 bytes causing a local OOG when copying
                          /// to memory.
                          /// @param _target The address to call
                          /// @param _gas The amount of gas to forward to the remote contract
                          /// @param _maxCopy The maximum number of bytes of returndata to copy
                          /// to memory.
                          /// @param _calldata The data to send to the remote contract
                          /// @return success and returndata, as `.call()`. Returndata is capped to
                          /// `_maxCopy` bytes.
                          function excessivelySafeStaticCall(
                              address _target,
                              uint256 _gas,
                              uint16 _maxCopy,
                              bytes memory _calldata
                          ) internal view returns (bool, bytes memory) {
                              // set up for assembly call
                              uint256 _toCopy;
                              bool _success;
                              bytes memory _returnData = new bytes(_maxCopy);
                              // dispatch message to recipient
                              // by assembly calling "handle" function
                              // we call via assembly to avoid memcopying a very large returndata
                              // returned by a malicious contract
                              assembly {
                                  _success := staticcall(
                                  _gas, // gas
                                  _target, // recipient
                                  add(_calldata, 0x20), // inloc
                                  mload(_calldata), // inlen
                                  0, // outloc
                                  0 // outlen
                                  )
                              // limit our copy to 256 bytes
                                  _toCopy := returndatasize()
                                  if gt(_toCopy, _maxCopy) {
                                      _toCopy := _maxCopy
                                  }
                              // Store the length of the copied bytes
                                  mstore(_returnData, _toCopy)
                              // copy the bytes from returndata[0:_toCopy]
                                  returndatacopy(add(_returnData, 0x20), 0, _toCopy)
                              }
                              return (_success, _returnData);
                          }
                          /**
                           * @notice Swaps function selectors in encoded contract calls
                           * @dev Allows reuse of encoded calldata for functions with identical
                           * argument types but different names. It simply swaps out the first 4 bytes
                           * for the new selector. This function modifies memory in place, and should
                           * only be used with caution.
                           * @param _newSelector The new 4-byte selector
                           * @param _buf The encoded contract args
                           */
                          function swapSelector(bytes4 _newSelector, bytes memory _buf)
                          internal
                          pure
                          {
                              require(_buf.length >= 4);
                              uint256 _mask = LOW_28_MASK;
                              assembly {
                              // load the first word of
                                  let _word := mload(add(_buf, 0x20))
                              // mask out the top 4 bytes
                              // /x
                                  _word := and(_word, _mask)
                                  _word := or(_newSelector, _word)
                                  mstore(add(_buf, 0x20), _word)
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.4;
                      import "hardhat-deploy/solc_0.8/proxy/Proxied.sol";
                      import {MerkleProofUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/MerkleProofUpgradeable.sol";
                      import {Initializable, ONFT721AUpgradeable, IERC721AUpgradeable} from "./contracts-upgradeable/token/onft/ERC721/ONFT721AUpgradeable.sol";
                      import "./interfaces/IDelegationRegistry.sol";
                      /**
                       * @title UtilityWenUpgradeable
                       * @notice Wen is a neW kind of NFT
                       * @author @Utility_wen
                       */
                      contract UtilityWenUpgradeable is Initializable, ONFT721AUpgradeable, Proxied {
                        /// @notice Maximum supply for the collection
                        uint public maxSupply; // n-1
                        /// @dev Treasury
                        address public treasury;
                        /// @notice Public mint
                        bool public isPublicOpen;
                        /// @dev The max per wallet (n-1)
                        uint public maxPerWallet;
                        /// @notice ETH mint price
                        uint public price;
                        /// @notice Live timestamp
                        uint public liveAt;
                        /// @notice Expires timestamp
                        uint public expiresAt;
                        /// @notice Guaranteed merkle root
                        bytes32 guaranteedMerkleRoot;
                        /// @notice Whitelist merkle root
                        bytes32 whitelistMerkleRoot;
                        /// @notice An address mapping mints
                        mapping(address => uint) public addressToMinted;
                        modifier isLive() {
                          require(isMintLive(), "!live");
                          _;
                        }
                        modifier isDelegate(address vault) {
                          bool isDelegateValid = IDelegationRegistry(delegationRegistryAddress)
                            .checkDelegateForContract(_msgSender(), vault, address(this));
                          require(isDelegateValid, "!invalid");
                          _;
                        }
                        modifier withinThreshold(uint _amount) {
                          require(totalSupply() + _amount < maxSupply, "!mintable");
                          require(
                            addressToMinted[_msgSenderERC721A()] + _amount < maxPerWallet,
                            "!able"
                          );
                          _;
                        }
                        modifier isWhitelisted(bytes32 _merkleRoot, bytes32[] calldata _proof) {
                          bytes32 leaf = keccak256(abi.encodePacked(_msgSenderERC721A()));
                          require(MerkleProofUpgradeable.verify(_proof, _merkleRoot, leaf), "!valid");
                          _;
                        }
                        modifier isCorrectPrice(uint _amount, uint _price) {
                          require(msg.value >= _amount * _price, "!funds");
                          _;
                        }
                        /// @custom:oz-upgrades-unsafe-allow constructor
                        constructor() {
                          _disableInitializers();
                        }
                        function initialize(
                          string memory _name,
                          string memory _symbol,
                          string memory baseURI_,
                          address _delegationRegistryAddress,
                          uint _minGasToTransfer,
                          address _lzEndpoint
                        ) public initializer {
                          __ONFT721AUpgradeable_init(
                            _name,
                            _symbol,
                            baseURI_,
                            _minGasToTransfer,
                            _lzEndpoint
                          );
                          // Set base treasury to deployer
                          treasury = payable(_msgSender());
                          // Mint setup
                          maxSupply = 10001;
                          price = 0.051 ether;
                          liveAt = 1687615200;
                          expiresAt = 1687701601;
                          maxPerWallet = 6;
                          isPublicOpen = false;
                        }
                        /**
                         * @dev Guarantee mint function
                         * @param _amount The amount of nfts to mint
                         * @param _proof The merkle proof for whitelist check
                         */
                        function guaranteedMint(uint _amount, bytes32[] calldata _proof)
                          external
                          payable
                          isLive
                          isCorrectPrice(_amount, price)
                          isWhitelisted(guaranteedMerkleRoot, _proof)
                          withinThreshold(_amount)
                        {
                          _processMint(_msgSenderERC721A(), _amount);
                        }
                        /**
                         * @dev Guarantee mint function
                         * @param _amount The amount of nfts to mint
                         * @param _proof The merkle proof for whitelist check
                         */
                        function whitelistMint(uint _amount, bytes32[] calldata _proof)
                          external
                          payable
                          isLive
                          isCorrectPrice(_amount, price)
                          isWhitelisted(whitelistMerkleRoot, _proof)
                          withinThreshold(_amount)
                        {
                          _processMint(_msgSenderERC721A(), _amount);
                        }
                        /**
                         * @dev Public mint function
                         * @param _amount The amount to mint
                         */
                        function mint(uint _amount)
                          external
                          payable
                          isLive
                          isCorrectPrice(_amount, price)
                          withinThreshold(_amount)
                        {
                          require(isPublicOpen, "!public");
                          _processMint(_msgSenderERC721A(), _amount);
                        }
                        /**
                         * @dev Process minting
                         * @param _to The address to associate
                         * @param _amount The amount to mint
                         */
                        function _processMint(address _to, uint _amount) internal {
                          addressToMinted[_to] += _amount;
                          _mint(_to, _amount);
                        }
                        /// @dev Check if mint is live
                        function isMintLive() public view returns (bool) {
                          return block.timestamp >= liveAt && block.timestamp <= expiresAt;
                        }
                        /**
                         * @notice Sets the collection max supply
                         * @param _maxSupply The max supply of the collection
                         */
                        function setMaxSupply(uint _maxSupply) external onlyOwner {
                          maxSupply = _maxSupply;
                        }
                        /**
                         * @notice Sets whether public minting is open
                         * @param _isPublicOpen boolean for public open state
                         */
                        function setPublicOpen(bool _isPublicOpen) external onlyOwner {
                          isPublicOpen = _isPublicOpen;
                        }
                        /**
                         * @notice Sets timestamps for live and expires timeframe
                         * @param _liveAt A unix timestamp for live date
                         * @param _expiresAt A unix timestamp for expiration date
                         */
                        function setMintWindow(uint _liveAt, uint _expiresAt) external onlyOwner {
                          liveAt = _liveAt;
                          expiresAt = _expiresAt;
                        }
                        /**
                         * @notice Sets the collection max per wallet
                         * @param _maxPerWallet The max per wallet
                         */
                        function setMaxPerWallet(uint _maxPerWallet) external onlyOwner {
                          maxPerWallet = _maxPerWallet;
                        }
                        /**
                         * @notice Sets eth price
                         * @param _price The price in wei
                         */
                        function setPrice(uint _price) external onlyOwner {
                          price = _price;
                        }
                        /**
                         * @notice Sets the treasury recipient
                         * @param _treasury The treasury address
                         */
                        function setTreasury(address _treasury) public onlyOwner {
                          treasury = payable(_treasury);
                        }
                        /**
                         * @notice Sets the guaranteed merkle root for the mint
                         * @param _guaranteedMerkleRoot The merkle root to set
                         */
                        function setGuaranteedMerkleRoot(bytes32 _guaranteedMerkleRoot)
                          external
                          onlyOwner
                        {
                          guaranteedMerkleRoot = _guaranteedMerkleRoot;
                        }
                        /**
                         * @notice Sets the whitelist merkle root for the mint
                         * @param _whitelistMerkleRoot The merkle root to set
                         */
                        function setWhitelistMerkleRoot(bytes32 _whitelistMerkleRoot)
                          external
                          onlyOwner
                        {
                          whitelistMerkleRoot = _whitelistMerkleRoot;
                        }
                        /// @notice Withdraws funds from contract
                        function withdraw() public onlyOwner {
                          uint balance = address(this).balance;
                          (bool success, ) = treasury.call{value: balance}("");
                          require(success, "!withdraw");
                        }
                        /**
                         * @dev Airdrop function
                         * @param _to The address to mint to
                         * @param _amount The amount to mint
                         */
                        function airdrop(address _to, uint _amount) external onlyOwner {
                          require(totalSupply() + _amount < maxSupply, "!enough");
                          _mint(_to, _amount);
                        }
                        /// @notice Withdraws NFTs from contract
                        function withdrawNFTAssets(uint[] calldata tokenIds) public onlyOwner {
                          for (uint i; i < tokenIds.length; i++) {
                            IERC721AUpgradeable(address(this)).transferFrom(
                              address(this),
                              _msgSenderERC721A(),
                              tokenIds[i]
                            );
                          }
                        }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      /**
                       * @dev This is a base contract to aid in writing upgradeable diamond facet 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.
                       */
                      import {ERC721A__InitializableStorage} from './ERC721A__InitializableStorage.sol';
                      abstract contract ERC721A__Initializable {
                          using ERC721A__InitializableStorage for ERC721A__InitializableStorage.Layout;
                          /**
                           * @dev Modifier to protect an initializer function from being invoked twice.
                           */
                          modifier initializerERC721A() {
                              // 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(
                                  ERC721A__InitializableStorage.layout()._initializing
                                      ? _isConstructor()
                                      : !ERC721A__InitializableStorage.layout()._initialized,
                                  'ERC721A__Initializable: contract is already initialized'
                              );
                              bool isTopLevelCall = !ERC721A__InitializableStorage.layout()._initializing;
                              if (isTopLevelCall) {
                                  ERC721A__InitializableStorage.layout()._initializing = true;
                                  ERC721A__InitializableStorage.layout()._initialized = true;
                              }
                              _;
                              if (isTopLevelCall) {
                                  ERC721A__InitializableStorage.layout()._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 onlyInitializingERC721A() {
                              require(
                                  ERC721A__InitializableStorage.layout()._initializing,
                                  'ERC721A__Initializable: contract is not initializing'
                              );
                              _;
                          }
                          /// @dev Returns true if and only if the function is running in the constructor
                          function _isConstructor() private view returns (bool) {
                              // extcodesize checks the size of the code stored in an address, and
                              // address returns the current address. Since the code is still not
                              // deployed when running a constructor, any checks on its code size will
                              // yield zero, making it an effective way to detect if a contract is
                              // under construction or not.
                              address self = address(this);
                              uint256 cs;
                              assembly {
                                  cs := extcodesize(self)
                              }
                              return cs == 0;
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      /**
                       * @dev This is a base storage for the  initialization function for upgradeable diamond facet contracts
                       **/
                      library ERC721A__InitializableStorage {
                          struct Layout {
                              /*
                               * Indicates that the contract has been initialized.
                               */
                              bool _initialized;
                              /*
                               * Indicates that the contract is in the process of being initialized.
                               */
                              bool _initializing;
                          }
                          bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.initializable.facet');
                          function layout() internal pure returns (Layout storage l) {
                              bytes32 slot = STORAGE_SLOT;
                              assembly {
                                  l.slot := slot
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      library ERC721AStorage {
                          // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
                          struct TokenApprovalRef {
                              address value;
                          }
                          struct Layout {
                              // =============================================================
                              //                            STORAGE
                              // =============================================================
                              // The next token ID to be minted.
                              uint256 _currentIndex;
                              // The number of tokens burned.
                              uint256 _burnCounter;
                              // Token name
                              string _name;
                              // Token symbol
                              string _symbol;
                              // Mapping from token ID to ownership details
                              // An empty struct value does not necessarily mean the token is unowned.
                              // See {_packedOwnershipOf} implementation for details.
                              //
                              // Bits Layout:
                              // - [0..159]   `addr`
                              // - [160..223] `startTimestamp`
                              // - [224]      `burned`
                              // - [225]      `nextInitialized`
                              // - [232..255] `extraData`
                              mapping(uint256 => uint256) _packedOwnerships;
                              // Mapping owner address to address data.
                              //
                              // Bits Layout:
                              // - [0..63]    `balance`
                              // - [64..127]  `numberMinted`
                              // - [128..191] `numberBurned`
                              // - [192..255] `aux`
                              mapping(address => uint256) _packedAddressData;
                              // Mapping from token ID to approved address.
                              mapping(uint256 => ERC721AStorage.TokenApprovalRef) _tokenApprovals;
                              // Mapping from owner to operator approvals
                              mapping(address => mapping(address => bool)) _operatorApprovals;
                          }
                          bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.ERC721A');
                          function layout() internal pure returns (Layout storage l) {
                              bytes32 slot = STORAGE_SLOT;
                              assembly {
                                  l.slot := slot
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // ERC721A Contracts v4.2.3
                      // Creator: Chiru Labs
                      pragma solidity ^0.8.4;
                      import './IERC721AUpgradeable.sol';
                      import {ERC721AStorage} from './ERC721AStorage.sol';
                      import './ERC721A__Initializable.sol';
                      /**
                       * @dev Interface of ERC721 token receiver.
                       */
                      interface ERC721A__IERC721ReceiverUpgradeable {
                          function onERC721Received(
                              address operator,
                              address from,
                              uint256 tokenId,
                              bytes calldata data
                          ) external returns (bytes4);
                      }
                      /**
                       * @title ERC721A
                       *
                       * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
                       * Non-Fungible Token Standard, including the Metadata extension.
                       * Optimized for lower gas during batch mints.
                       *
                       * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
                       * starting from `_startTokenId()`.
                       *
                       * Assumptions:
                       *
                       * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
                       * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
                       */
                      contract ERC721AUpgradeable is ERC721A__Initializable, IERC721AUpgradeable {
                          using ERC721AStorage for ERC721AStorage.Layout;
                          // =============================================================
                          //                           CONSTANTS
                          // =============================================================
                          // Mask of an entry in packed address data.
                          uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
                          // The bit position of `numberMinted` in packed address data.
                          uint256 private constant _BITPOS_NUMBER_MINTED = 64;
                          // The bit position of `numberBurned` in packed address data.
                          uint256 private constant _BITPOS_NUMBER_BURNED = 128;
                          // The bit position of `aux` in packed address data.
                          uint256 private constant _BITPOS_AUX = 192;
                          // Mask of all 256 bits in packed address data except the 64 bits for `aux`.
                          uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
                          // The bit position of `startTimestamp` in packed ownership.
                          uint256 private constant _BITPOS_START_TIMESTAMP = 160;
                          // The bit mask of the `burned` bit in packed ownership.
                          uint256 private constant _BITMASK_BURNED = 1 << 224;
                          // The bit position of the `nextInitialized` bit in packed ownership.
                          uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
                          // The bit mask of the `nextInitialized` bit in packed ownership.
                          uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
                          // The bit position of `extraData` in packed ownership.
                          uint256 private constant _BITPOS_EXTRA_DATA = 232;
                          // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
                          uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
                          // The mask of the lower 160 bits for addresses.
                          uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
                          // The maximum `quantity` that can be minted with {_mintERC2309}.
                          // This limit is to prevent overflows on the address data entries.
                          // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
                          // is required to cause an overflow, which is unrealistic.
                          uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
                          // The `Transfer` event signature is given by:
                          // `keccak256(bytes("Transfer(address,address,uint256)"))`.
                          bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
                              0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
                          // =============================================================
                          //                          CONSTRUCTOR
                          // =============================================================
                          function __ERC721A_init(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
                              __ERC721A_init_unchained(name_, symbol_);
                          }
                          function __ERC721A_init_unchained(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
                              ERC721AStorage.layout()._name = name_;
                              ERC721AStorage.layout()._symbol = symbol_;
                              ERC721AStorage.layout()._currentIndex = _startTokenId();
                          }
                          // =============================================================
                          //                   TOKEN COUNTING OPERATIONS
                          // =============================================================
                          /**
                           * @dev Returns the starting token ID.
                           * To change the starting token ID, please override this function.
                           */
                          function _startTokenId() internal view virtual returns (uint256) {
                              return 0;
                          }
                          /**
                           * @dev Returns the next token ID to be minted.
                           */
                          function _nextTokenId() internal view virtual returns (uint256) {
                              return ERC721AStorage.layout()._currentIndex;
                          }
                          /**
                           * @dev Returns the total number of tokens in existence.
                           * Burned tokens will reduce the count.
                           * To get the total number of tokens minted, please see {_totalMinted}.
                           */
                          function totalSupply() public view virtual override returns (uint256) {
                              // Counter underflow is impossible as _burnCounter cannot be incremented
                              // more than `_currentIndex - _startTokenId()` times.
                              unchecked {
                                  return ERC721AStorage.layout()._currentIndex - ERC721AStorage.layout()._burnCounter - _startTokenId();
                              }
                          }
                          /**
                           * @dev Returns the total amount of tokens minted in the contract.
                           */
                          function _totalMinted() internal view virtual returns (uint256) {
                              // Counter underflow is impossible as `_currentIndex` does not decrement,
                              // and it is initialized to `_startTokenId()`.
                              unchecked {
                                  return ERC721AStorage.layout()._currentIndex - _startTokenId();
                              }
                          }
                          /**
                           * @dev Returns the total number of tokens burned.
                           */
                          function _totalBurned() internal view virtual returns (uint256) {
                              return ERC721AStorage.layout()._burnCounter;
                          }
                          // =============================================================
                          //                    ADDRESS DATA OPERATIONS
                          // =============================================================
                          /**
                           * @dev Returns the number of tokens in `owner`'s account.
                           */
                          function balanceOf(address owner) public view virtual override returns (uint256) {
                              if (owner == address(0)) revert BalanceQueryForZeroAddress();
                              return ERC721AStorage.layout()._packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
                          }
                          /**
                           * Returns the number of tokens minted by `owner`.
                           */
                          function _numberMinted(address owner) internal view returns (uint256) {
                              return
                                  (ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
                          }
                          /**
                           * Returns the number of tokens burned by or on behalf of `owner`.
                           */
                          function _numberBurned(address owner) internal view returns (uint256) {
                              return
                                  (ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
                          }
                          /**
                           * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
                           */
                          function _getAux(address owner) internal view returns (uint64) {
                              return uint64(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_AUX);
                          }
                          /**
                           * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
                           * If there are multiple variables, please pack them into a uint64.
                           */
                          function _setAux(address owner, uint64 aux) internal virtual {
                              uint256 packed = ERC721AStorage.layout()._packedAddressData[owner];
                              uint256 auxCasted;
                              // Cast `aux` with assembly to avoid redundant masking.
                              assembly {
                                  auxCasted := aux
                              }
                              packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
                              ERC721AStorage.layout()._packedAddressData[owner] = packed;
                          }
                          // =============================================================
                          //                            IERC165
                          // =============================================================
                          /**
                           * @dev Returns true if this contract implements the interface defined by
                           * `interfaceId`. See the corresponding
                           * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
                           * to learn more about how these ids are created.
                           *
                           * This function call must use less than 30000 gas.
                           */
                          function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                              // The interface IDs are constants representing the first 4 bytes
                              // of the XOR of all function selectors in the interface.
                              // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
                              // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
                              return
                                  interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
                                  interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
                                  interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
                          }
                          // =============================================================
                          //                        IERC721Metadata
                          // =============================================================
                          /**
                           * @dev Returns the token collection name.
                           */
                          function name() public view virtual override returns (string memory) {
                              return ERC721AStorage.layout()._name;
                          }
                          /**
                           * @dev Returns the token collection symbol.
                           */
                          function symbol() public view virtual override returns (string memory) {
                              return ERC721AStorage.layout()._symbol;
                          }
                          /**
                           * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
                           */
                          function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
                              if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
                              string memory baseURI = _baseURI();
                              return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
                          }
                          /**
                           * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
                           * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
                           * by default, it can be overridden in child contracts.
                           */
                          function _baseURI() internal view virtual returns (string memory) {
                              return '';
                          }
                          // =============================================================
                          //                     OWNERSHIPS OPERATIONS
                          // =============================================================
                          /**
                           * @dev Returns the owner of the `tokenId` token.
                           *
                           * Requirements:
                           *
                           * - `tokenId` must exist.
                           */
                          function ownerOf(uint256 tokenId) public view virtual override returns (address) {
                              return address(uint160(_packedOwnershipOf(tokenId)));
                          }
                          /**
                           * @dev Gas spent here starts off proportional to the maximum mint batch size.
                           * It gradually moves to O(1) as tokens get transferred around over time.
                           */
                          function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
                              return _unpackedOwnership(_packedOwnershipOf(tokenId));
                          }
                          /**
                           * @dev Returns the unpacked `TokenOwnership` struct at `index`.
                           */
                          function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
                              return _unpackedOwnership(ERC721AStorage.layout()._packedOwnerships[index]);
                          }
                          /**
                           * @dev Initializes the ownership slot minted at `index` for efficiency purposes.
                           */
                          function _initializeOwnershipAt(uint256 index) internal virtual {
                              if (ERC721AStorage.layout()._packedOwnerships[index] == 0) {
                                  ERC721AStorage.layout()._packedOwnerships[index] = _packedOwnershipOf(index);
                              }
                          }
                          /**
                           * Returns the packed ownership data of `tokenId`.
                           */
                          function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {
                              if (_startTokenId() <= tokenId) {
                                  packed = ERC721AStorage.layout()._packedOwnerships[tokenId];
                                  // If not burned.
                                  if (packed & _BITMASK_BURNED == 0) {
                                      // If the data at the starting slot does not exist, start the scan.
                                      if (packed == 0) {
                                          if (tokenId >= ERC721AStorage.layout()._currentIndex) revert OwnerQueryForNonexistentToken();
                                          // Invariant:
                                          // There will always be an initialized ownership slot
                                          // (i.e. `ownership.addr != address(0) && ownership.burned == false`)
                                          // before an unintialized ownership slot
                                          // (i.e. `ownership.addr == address(0) && ownership.burned == false`)
                                          // Hence, `tokenId` will not underflow.
                                          //
                                          // We can directly compare the packed value.
                                          // If the address is zero, packed will be zero.
                                          for (;;) {
                                              unchecked {
                                                  packed = ERC721AStorage.layout()._packedOwnerships[--tokenId];
                                              }
                                              if (packed == 0) continue;
                                              return packed;
                                          }
                                      }
                                      // Otherwise, the data exists and is not burned. We can skip the scan.
                                      // This is possible because we have already achieved the target condition.
                                      // This saves 2143 gas on transfers of initialized tokens.
                                      return packed;
                                  }
                              }
                              revert OwnerQueryForNonexistentToken();
                          }
                          /**
                           * @dev Returns the unpacked `TokenOwnership` struct from `packed`.
                           */
                          function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
                              ownership.addr = address(uint160(packed));
                              ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
                              ownership.burned = packed & _BITMASK_BURNED != 0;
                              ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
                          }
                          /**
                           * @dev Packs ownership data into a single uint256.
                           */
                          function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
                              assembly {
                                  // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
                                  owner := and(owner, _BITMASK_ADDRESS)
                                  // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
                                  result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
                              }
                          }
                          /**
                           * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
                           */
                          function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
                              // For branchless setting of the `nextInitialized` flag.
                              assembly {
                                  // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
                                  result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
                              }
                          }
                          // =============================================================
                          //                      APPROVAL OPERATIONS
                          // =============================================================
                          /**
                           * @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}.
                           *
                           * Requirements:
                           *
                           * - The caller must own the token or be an approved operator.
                           */
                          function approve(address to, uint256 tokenId) public payable virtual override {
                              _approve(to, tokenId, true);
                          }
                          /**
                           * @dev Returns the account approved for `tokenId` token.
                           *
                           * Requirements:
                           *
                           * - `tokenId` must exist.
                           */
                          function getApproved(uint256 tokenId) public view virtual override returns (address) {
                              if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
                              return ERC721AStorage.layout()._tokenApprovals[tokenId].value;
                          }
                          /**
                           * @dev Approve or remove `operator` as an operator for the caller.
                           * Operators can call {transferFrom} or {safeTransferFrom}
                           * for any token owned by the caller.
                           *
                           * Requirements:
                           *
                           * - The `operator` cannot be the caller.
                           *
                           * Emits an {ApprovalForAll} event.
                           */
                          function setApprovalForAll(address operator, bool approved) public virtual override {
                              ERC721AStorage.layout()._operatorApprovals[_msgSenderERC721A()][operator] = approved;
                              emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
                          }
                          /**
                           * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
                           *
                           * See {setApprovalForAll}.
                           */
                          function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
                              return ERC721AStorage.layout()._operatorApprovals[owner][operator];
                          }
                          /**
                           * @dev Returns whether `tokenId` exists.
                           *
                           * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
                           *
                           * Tokens start existing when they are minted. See {_mint}.
                           */
                          function _exists(uint256 tokenId) internal view virtual returns (bool) {
                              return
                                  _startTokenId() <= tokenId &&
                                  tokenId < ERC721AStorage.layout()._currentIndex && // If within bounds,
                                  ERC721AStorage.layout()._packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
                          }
                          /**
                           * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
                           */
                          function _isSenderApprovedOrOwner(
                              address approvedAddress,
                              address owner,
                              address msgSender
                          ) private pure returns (bool result) {
                              assembly {
                                  // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
                                  owner := and(owner, _BITMASK_ADDRESS)
                                  // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
                                  msgSender := and(msgSender, _BITMASK_ADDRESS)
                                  // `msgSender == owner || msgSender == approvedAddress`.
                                  result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
                              }
                          }
                          /**
                           * @dev Returns the storage slot and value for the approved address of `tokenId`.
                           */
                          function _getApprovedSlotAndAddress(uint256 tokenId)
                              private
                              view
                              returns (uint256 approvedAddressSlot, address approvedAddress)
                          {
                              ERC721AStorage.TokenApprovalRef storage tokenApproval = ERC721AStorage.layout()._tokenApprovals[tokenId];
                              // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
                              assembly {
                                  approvedAddressSlot := tokenApproval.slot
                                  approvedAddress := sload(approvedAddressSlot)
                              }
                          }
                          // =============================================================
                          //                      TRANSFER OPERATIONS
                          // =============================================================
                          /**
                           * @dev Transfers `tokenId` from `from` to `to`.
                           *
                           * Requirements:
                           *
                           * - `from` cannot be the zero address.
                           * - `to` cannot be the zero address.
                           * - `tokenId` token must be owned by `from`.
                           * - If the caller is not `from`, it must be approved to move this token
                           * by either {approve} or {setApprovalForAll}.
                           *
                           * Emits a {Transfer} event.
                           */
                          function transferFrom(
                              address from,
                              address to,
                              uint256 tokenId
                          ) public payable virtual override {
                              uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
                              if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();
                              (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
                              // The nested ifs save around 20+ gas over a compound boolean condition.
                              if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                                  if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
                              if (to == address(0)) revert TransferToZeroAddress();
                              _beforeTokenTransfers(from, to, tokenId, 1);
                              // Clear approvals from the previous owner.
                              assembly {
                                  if approvedAddress {
                                      // This is equivalent to `delete _tokenApprovals[tokenId]`.
                                      sstore(approvedAddressSlot, 0)
                                  }
                              }
                              // Underflow of the sender's balance is impossible because we check for
                              // ownership above and the recipient's balance can't realistically overflow.
                              // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
                              unchecked {
                                  // We can directly increment and decrement the balances.
                                  --ERC721AStorage.layout()._packedAddressData[from]; // Updates: `balance -= 1`.
                                  ++ERC721AStorage.layout()._packedAddressData[to]; // Updates: `balance += 1`.
                                  // Updates:
                                  // - `address` to the next owner.
                                  // - `startTimestamp` to the timestamp of transfering.
                                  // - `burned` to `false`.
                                  // - `nextInitialized` to `true`.
                                  ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
                                      to,
                                      _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
                                  );
                                  // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
                                  if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                                      uint256 nextTokenId = tokenId + 1;
                                      // If the next slot's address is zero and not burned (i.e. packed value is zero).
                                      if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
                                          // If the next slot is within bounds.
                                          if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
                                              // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                                              ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
                                          }
                                      }
                                  }
                              }
                              emit Transfer(from, to, tokenId);
                              _afterTokenTransfers(from, to, tokenId, 1);
                          }
                          /**
                           * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
                           */
                          function safeTransferFrom(
                              address from,
                              address to,
                              uint256 tokenId
                          ) public payable virtual override {
                              safeTransferFrom(from, to, tokenId, '');
                          }
                          /**
                           * @dev Safely transfers `tokenId` token from `from` to `to`.
                           *
                           * Requirements:
                           *
                           * - `from` cannot be the zero address.
                           * - `to` cannot be the zero address.
                           * - `tokenId` token must exist and be owned by `from`.
                           * - If the caller is not `from`, it must be approved to move this token
                           * by either {approve} or {setApprovalForAll}.
                           * - If `to` refers to a smart contract, it must implement
                           * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
                           *
                           * Emits a {Transfer} event.
                           */
                          function safeTransferFrom(
                              address from,
                              address to,
                              uint256 tokenId,
                              bytes memory _data
                          ) public payable virtual override {
                              transferFrom(from, to, tokenId);
                              if (to.code.length != 0)
                                  if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                                      revert TransferToNonERC721ReceiverImplementer();
                                  }
                          }
                          /**
                           * @dev Hook that is called before a set of serially-ordered token IDs
                           * are about to be transferred. This includes minting.
                           * And also called before burning one token.
                           *
                           * `startTokenId` - the first token ID to be transferred.
                           * `quantity` - the amount to be transferred.
                           *
                           * Calling conditions:
                           *
                           * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
                           * transferred to `to`.
                           * - When `from` is zero, `tokenId` will be minted for `to`.
                           * - When `to` is zero, `tokenId` will be burned by `from`.
                           * - `from` and `to` are never both zero.
                           */
                          function _beforeTokenTransfers(
                              address from,
                              address to,
                              uint256 startTokenId,
                              uint256 quantity
                          ) internal virtual {}
                          /**
                           * @dev Hook that is called after a set of serially-ordered token IDs
                           * have been transferred. This includes minting.
                           * And also called after one token has been burned.
                           *
                           * `startTokenId` - the first token ID to be transferred.
                           * `quantity` - the amount to be transferred.
                           *
                           * Calling conditions:
                           *
                           * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
                           * transferred to `to`.
                           * - When `from` is zero, `tokenId` has been minted for `to`.
                           * - When `to` is zero, `tokenId` has been burned by `from`.
                           * - `from` and `to` are never both zero.
                           */
                          function _afterTokenTransfers(
                              address from,
                              address to,
                              uint256 startTokenId,
                              uint256 quantity
                          ) internal virtual {}
                          /**
                           * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
                           *
                           * `from` - Previous owner of the given token ID.
                           * `to` - Target address that will receive the token.
                           * `tokenId` - Token ID to be transferred.
                           * `_data` - Optional data to send along with the call.
                           *
                           * Returns whether the call correctly returned the expected magic value.
                           */
                          function _checkContractOnERC721Received(
                              address from,
                              address to,
                              uint256 tokenId,
                              bytes memory _data
                          ) private returns (bool) {
                              try
                                  ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data)
                              returns (bytes4 retval) {
                                  return retval == ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received.selector;
                              } catch (bytes memory reason) {
                                  if (reason.length == 0) {
                                      revert TransferToNonERC721ReceiverImplementer();
                                  } else {
                                      assembly {
                                          revert(add(32, reason), mload(reason))
                                      }
                                  }
                              }
                          }
                          // =============================================================
                          //                        MINT OPERATIONS
                          // =============================================================
                          /**
                           * @dev Mints `quantity` tokens and transfers them to `to`.
                           *
                           * Requirements:
                           *
                           * - `to` cannot be the zero address.
                           * - `quantity` must be greater than 0.
                           *
                           * Emits a {Transfer} event for each mint.
                           */
                          function _mint(address to, uint256 quantity) internal virtual {
                              uint256 startTokenId = ERC721AStorage.layout()._currentIndex;
                              if (quantity == 0) revert MintZeroQuantity();
                              _beforeTokenTransfers(address(0), to, startTokenId, quantity);
                              // Overflows are incredibly unrealistic.
                              // `balance` and `numberMinted` have a maximum limit of 2**64.
                              // `tokenId` has a maximum limit of 2**256.
                              unchecked {
                                  // Updates:
                                  // - `balance += quantity`.
                                  // - `numberMinted += quantity`.
                                  //
                                  // We can directly add to the `balance` and `numberMinted`.
                                  ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
                                  // Updates:
                                  // - `address` to the owner.
                                  // - `startTimestamp` to the timestamp of minting.
                                  // - `burned` to `false`.
                                  // - `nextInitialized` to `quantity == 1`.
                                  ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
                                      to,
                                      _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                                  );
                                  uint256 toMasked;
                                  uint256 end = startTokenId + quantity;
                                  // Use assembly to loop and emit the `Transfer` event for gas savings.
                                  // The duplicated `log4` removes an extra check and reduces stack juggling.
                                  // The assembly, together with the surrounding Solidity code, have been
                                  // delicately arranged to nudge the compiler into producing optimized opcodes.
                                  assembly {
                                      // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
                                      toMasked := and(to, _BITMASK_ADDRESS)
                                      // Emit the `Transfer` event.
                                      log4(
                                          0, // Start of data (0, since no data).
                                          0, // End of data (0, since no data).
                                          _TRANSFER_EVENT_SIGNATURE, // Signature.
                                          0, // `address(0)`.
                                          toMasked, // `to`.
                                          startTokenId // `tokenId`.
                                      )
                                      // The `iszero(eq(,))` check ensures that large values of `quantity`
                                      // that overflows uint256 will make the loop run out of gas.
                                      // The compiler will optimize the `iszero` away for performance.
                                      for {
                                          let tokenId := add(startTokenId, 1)
                                      } iszero(eq(tokenId, end)) {
                                          tokenId := add(tokenId, 1)
                                      } {
                                          // Emit the `Transfer` event. Similar to above.
                                          log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                                      }
                                  }
                                  if (toMasked == 0) revert MintToZeroAddress();
                                  ERC721AStorage.layout()._currentIndex = end;
                              }
                              _afterTokenTransfers(address(0), to, startTokenId, quantity);
                          }
                          /**
                           * @dev Mints `quantity` tokens and transfers them to `to`.
                           *
                           * This function is intended for efficient minting only during contract creation.
                           *
                           * It emits only one {ConsecutiveTransfer} as defined in
                           * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
                           * instead of a sequence of {Transfer} event(s).
                           *
                           * Calling this function outside of contract creation WILL make your contract
                           * non-compliant with the ERC721 standard.
                           * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
                           * {ConsecutiveTransfer} event is only permissible during contract creation.
                           *
                           * Requirements:
                           *
                           * - `to` cannot be the zero address.
                           * - `quantity` must be greater than 0.
                           *
                           * Emits a {ConsecutiveTransfer} event.
                           */
                          function _mintERC2309(address to, uint256 quantity) internal virtual {
                              uint256 startTokenId = ERC721AStorage.layout()._currentIndex;
                              if (to == address(0)) revert MintToZeroAddress();
                              if (quantity == 0) revert MintZeroQuantity();
                              if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();
                              _beforeTokenTransfers(address(0), to, startTokenId, quantity);
                              // Overflows are unrealistic due to the above check for `quantity` to be below the limit.
                              unchecked {
                                  // Updates:
                                  // - `balance += quantity`.
                                  // - `numberMinted += quantity`.
                                  //
                                  // We can directly add to the `balance` and `numberMinted`.
                                  ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
                                  // Updates:
                                  // - `address` to the owner.
                                  // - `startTimestamp` to the timestamp of minting.
                                  // - `burned` to `false`.
                                  // - `nextInitialized` to `quantity == 1`.
                                  ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
                                      to,
                                      _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                                  );
                                  emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
                                  ERC721AStorage.layout()._currentIndex = startTokenId + quantity;
                              }
                              _afterTokenTransfers(address(0), to, startTokenId, quantity);
                          }
                          /**
                           * @dev Safely mints `quantity` tokens and transfers them to `to`.
                           *
                           * Requirements:
                           *
                           * - If `to` refers to a smart contract, it must implement
                           * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
                           * - `quantity` must be greater than 0.
                           *
                           * See {_mint}.
                           *
                           * Emits a {Transfer} event for each mint.
                           */
                          function _safeMint(
                              address to,
                              uint256 quantity,
                              bytes memory _data
                          ) internal virtual {
                              _mint(to, quantity);
                              unchecked {
                                  if (to.code.length != 0) {
                                      uint256 end = ERC721AStorage.layout()._currentIndex;
                                      uint256 index = end - quantity;
                                      do {
                                          if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                                              revert TransferToNonERC721ReceiverImplementer();
                                          }
                                      } while (index < end);
                                      // Reentrancy protection.
                                      if (ERC721AStorage.layout()._currentIndex != end) revert();
                                  }
                              }
                          }
                          /**
                           * @dev Equivalent to `_safeMint(to, quantity, '')`.
                           */
                          function _safeMint(address to, uint256 quantity) internal virtual {
                              _safeMint(to, quantity, '');
                          }
                          // =============================================================
                          //                       APPROVAL OPERATIONS
                          // =============================================================
                          /**
                           * @dev Equivalent to `_approve(to, tokenId, false)`.
                           */
                          function _approve(address to, uint256 tokenId) internal virtual {
                              _approve(to, tokenId, false);
                          }
                          /**
                           * @dev Gives permission to `to` to transfer `tokenId` token to another account.
                           * The approval is cleared when the token is transferred.
                           *
                           * Only a single account can be approved at a time, so approving the
                           * zero address clears previous approvals.
                           *
                           * Requirements:
                           *
                           * - `tokenId` must exist.
                           *
                           * Emits an {Approval} event.
                           */
                          function _approve(
                              address to,
                              uint256 tokenId,
                              bool approvalCheck
                          ) internal virtual {
                              address owner = ownerOf(tokenId);
                              if (approvalCheck)
                                  if (_msgSenderERC721A() != owner)
                                      if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                                          revert ApprovalCallerNotOwnerNorApproved();
                                      }
                              ERC721AStorage.layout()._tokenApprovals[tokenId].value = to;
                              emit Approval(owner, to, tokenId);
                          }
                          // =============================================================
                          //                        BURN OPERATIONS
                          // =============================================================
                          /**
                           * @dev Equivalent to `_burn(tokenId, false)`.
                           */
                          function _burn(uint256 tokenId) internal virtual {
                              _burn(tokenId, false);
                          }
                          /**
                           * @dev Destroys `tokenId`.
                           * The approval is cleared when the token is burned.
                           *
                           * Requirements:
                           *
                           * - `tokenId` must exist.
                           *
                           * Emits a {Transfer} event.
                           */
                          function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
                              uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
                              address from = address(uint160(prevOwnershipPacked));
                              (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
                              if (approvalCheck) {
                                  // The nested ifs save around 20+ gas over a compound boolean condition.
                                  if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                                      if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
                              }
                              _beforeTokenTransfers(from, address(0), tokenId, 1);
                              // Clear approvals from the previous owner.
                              assembly {
                                  if approvedAddress {
                                      // This is equivalent to `delete _tokenApprovals[tokenId]`.
                                      sstore(approvedAddressSlot, 0)
                                  }
                              }
                              // Underflow of the sender's balance is impossible because we check for
                              // ownership above and the recipient's balance can't realistically overflow.
                              // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
                              unchecked {
                                  // Updates:
                                  // - `balance -= 1`.
                                  // - `numberBurned += 1`.
                                  //
                                  // We can directly decrement the balance, and increment the number burned.
                                  // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
                                  ERC721AStorage.layout()._packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
                                  // Updates:
                                  // - `address` to the last owner.
                                  // - `startTimestamp` to the timestamp of burning.
                                  // - `burned` to `true`.
                                  // - `nextInitialized` to `true`.
                                  ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
                                      from,
                                      (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
                                  );
                                  // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
                                  if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                                      uint256 nextTokenId = tokenId + 1;
                                      // If the next slot's address is zero and not burned (i.e. packed value is zero).
                                      if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
                                          // If the next slot is within bounds.
                                          if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
                                              // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                                              ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
                                          }
                                      }
                                  }
                              }
                              emit Transfer(from, address(0), tokenId);
                              _afterTokenTransfers(from, address(0), tokenId, 1);
                              // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
                              unchecked {
                                  ERC721AStorage.layout()._burnCounter++;
                              }
                          }
                          // =============================================================
                          //                     EXTRA DATA OPERATIONS
                          // =============================================================
                          /**
                           * @dev Directly sets the extra data for the ownership data `index`.
                           */
                          function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
                              uint256 packed = ERC721AStorage.layout()._packedOwnerships[index];
                              if (packed == 0) revert OwnershipNotInitializedForExtraData();
                              uint256 extraDataCasted;
                              // Cast `extraData` with assembly to avoid redundant masking.
                              assembly {
                                  extraDataCasted := extraData
                              }
                              packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
                              ERC721AStorage.layout()._packedOwnerships[index] = packed;
                          }
                          /**
                           * @dev Called during each token transfer to set the 24bit `extraData` field.
                           * Intended to be overridden by the cosumer contract.
                           *
                           * `previousExtraData` - the value of `extraData` before transfer.
                           *
                           * Calling conditions:
                           *
                           * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
                           * transferred to `to`.
                           * - When `from` is zero, `tokenId` will be minted for `to`.
                           * - When `to` is zero, `tokenId` will be burned by `from`.
                           * - `from` and `to` are never both zero.
                           */
                          function _extraData(
                              address from,
                              address to,
                              uint24 previousExtraData
                          ) internal view virtual returns (uint24) {}
                          /**
                           * @dev Returns the next extra data for the packed ownership data.
                           * The returned result is shifted into position.
                           */
                          function _nextExtraData(
                              address from,
                              address to,
                              uint256 prevOwnershipPacked
                          ) private view returns (uint256) {
                              uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
                              return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
                          }
                          // =============================================================
                          //                       OTHER OPERATIONS
                          // =============================================================
                          /**
                           * @dev Returns the message sender (defaults to `msg.sender`).
                           *
                           * If you are writing GSN compatible contracts, you need to override this function.
                           */
                          function _msgSenderERC721A() internal view virtual returns (address) {
                              return msg.sender;
                          }
                          /**
                           * @dev Converts a uint256 to its ASCII string decimal representation.
                           */
                          function _toString(uint256 value) internal pure virtual returns (string memory str) {
                              assembly {
                                  // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
                                  // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
                                  // We will need 1 word for the trailing zeros padding, 1 word for the length,
                                  // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
                                  let m := add(mload(0x40), 0xa0)
                                  // Update the free memory pointer to allocate.
                                  mstore(0x40, m)
                                  // Assign the `str` to the end.
                                  str := sub(m, 0x20)
                                  // Zeroize the slot after the string.
                                  mstore(str, 0)
                                  // Cache the end of the memory to calculate the length later.
                                  let end := str
                                  // We write the string from rightmost digit to leftmost digit.
                                  // The following is essentially a do-while loop that also handles the zero case.
                                  // prettier-ignore
                                  for { let temp := value } 1 {} {
                                      str := sub(str, 1)
                                      // Write the character to the pointer.
                                      // The ASCII index of the '0' character is 48.
                                      mstore8(str, add(48, mod(temp, 10)))
                                      // Keep dividing `temp` until zero.
                                      temp := div(temp, 10)
                                      // prettier-ignore
                                      if iszero(temp) { break }
                                  }
                                  let length := sub(end, str)
                                  // Move the pointer 32 bytes leftwards to make room for the length.
                                  str := sub(str, 0x20)
                                  // Store the length.
                                  mstore(str, length)
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // ERC721A Contracts v4.2.3
                      // Creator: Chiru Labs
                      pragma solidity ^0.8.4;
                      import './IERC721AQueryableUpgradeable.sol';
                      import '../ERC721AUpgradeable.sol';
                      import '../ERC721A__Initializable.sol';
                      /**
                       * @title ERC721AQueryable.
                       *
                       * @dev ERC721A subclass with convenience query functions.
                       */
                      abstract contract ERC721AQueryableUpgradeable is
                          ERC721A__Initializable,
                          ERC721AUpgradeable,
                          IERC721AQueryableUpgradeable
                      {
                          function __ERC721AQueryable_init() internal onlyInitializingERC721A {
                              __ERC721AQueryable_init_unchained();
                          }
                          function __ERC721AQueryable_init_unchained() internal onlyInitializingERC721A {}
                          /**
                           * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
                           *
                           * If the `tokenId` is out of bounds:
                           *
                           * - `addr = address(0)`
                           * - `startTimestamp = 0`
                           * - `burned = false`
                           * - `extraData = 0`
                           *
                           * If the `tokenId` is burned:
                           *
                           * - `addr = <Address of owner before token was burned>`
                           * - `startTimestamp = <Timestamp when token was burned>`
                           * - `burned = true`
                           * - `extraData = <Extra data when token was burned>`
                           *
                           * Otherwise:
                           *
                           * - `addr = <Address of owner>`
                           * - `startTimestamp = <Timestamp of start of ownership>`
                           * - `burned = false`
                           * - `extraData = <Extra data at start of ownership>`
                           */
                          function explicitOwnershipOf(uint256 tokenId) public view virtual override returns (TokenOwnership memory) {
                              TokenOwnership memory ownership;
                              if (tokenId < _startTokenId() || tokenId >= _nextTokenId()) {
                                  return ownership;
                              }
                              ownership = _ownershipAt(tokenId);
                              if (ownership.burned) {
                                  return ownership;
                              }
                              return _ownershipOf(tokenId);
                          }
                          /**
                           * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order.
                           * See {ERC721AQueryable-explicitOwnershipOf}
                           */
                          function explicitOwnershipsOf(uint256[] calldata tokenIds)
                              external
                              view
                              virtual
                              override
                              returns (TokenOwnership[] memory)
                          {
                              unchecked {
                                  uint256 tokenIdsLength = tokenIds.length;
                                  TokenOwnership[] memory ownerships = new TokenOwnership[](tokenIdsLength);
                                  for (uint256 i; i != tokenIdsLength; ++i) {
                                      ownerships[i] = explicitOwnershipOf(tokenIds[i]);
                                  }
                                  return ownerships;
                              }
                          }
                          /**
                           * @dev Returns an array of token IDs owned by `owner`,
                           * in the range [`start`, `stop`)
                           * (i.e. `start <= tokenId < stop`).
                           *
                           * This function allows for tokens to be queried if the collection
                           * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}.
                           *
                           * Requirements:
                           *
                           * - `start < stop`
                           */
                          function tokensOfOwnerIn(
                              address owner,
                              uint256 start,
                              uint256 stop
                          ) external view virtual override returns (uint256[] memory) {
                              unchecked {
                                  if (start >= stop) revert InvalidQueryRange();
                                  uint256 tokenIdsIdx;
                                  uint256 stopLimit = _nextTokenId();
                                  // Set `start = max(start, _startTokenId())`.
                                  if (start < _startTokenId()) {
                                      start = _startTokenId();
                                  }
                                  // Set `stop = min(stop, stopLimit)`.
                                  if (stop > stopLimit) {
                                      stop = stopLimit;
                                  }
                                  uint256 tokenIdsMaxLength = balanceOf(owner);
                                  // Set `tokenIdsMaxLength = min(balanceOf(owner), stop - start)`,
                                  // to cater for cases where `balanceOf(owner)` is too big.
                                  if (start < stop) {
                                      uint256 rangeLength = stop - start;
                                      if (rangeLength < tokenIdsMaxLength) {
                                          tokenIdsMaxLength = rangeLength;
                                      }
                                  } else {
                                      tokenIdsMaxLength = 0;
                                  }
                                  uint256[] memory tokenIds = new uint256[](tokenIdsMaxLength);
                                  if (tokenIdsMaxLength == 0) {
                                      return tokenIds;
                                  }
                                  // We need to call `explicitOwnershipOf(start)`,
                                  // because the slot at `start` may not be initialized.
                                  TokenOwnership memory ownership = explicitOwnershipOf(start);
                                  address currOwnershipAddr;
                                  // If the starting slot exists (i.e. not burned), initialize `currOwnershipAddr`.
                                  // `ownership.address` will not be zero, as `start` is clamped to the valid token ID range.
                                  if (!ownership.burned) {
                                      currOwnershipAddr = ownership.addr;
                                  }
                                  for (uint256 i = start; i != stop && tokenIdsIdx != tokenIdsMaxLength; ++i) {
                                      ownership = _ownershipAt(i);
                                      if (ownership.burned) {
                                          continue;
                                      }
                                      if (ownership.addr != address(0)) {
                                          currOwnershipAddr = ownership.addr;
                                      }
                                      if (currOwnershipAddr == owner) {
                                          tokenIds[tokenIdsIdx++] = i;
                                      }
                                  }
                                  // Downsize the array to fit.
                                  assembly {
                                      mstore(tokenIds, tokenIdsIdx)
                                  }
                                  return tokenIds;
                              }
                          }
                          /**
                           * @dev Returns an array of token IDs owned by `owner`.
                           *
                           * This function scans the ownership mapping and is O(`totalSupply`) in complexity.
                           * It is meant to be called off-chain.
                           *
                           * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into
                           * multiple smaller scans if the collection is large enough to cause
                           * an out-of-gas error (10K collections should be fine).
                           */
                          function tokensOfOwner(address owner) external view virtual override returns (uint256[] memory) {
                              unchecked {
                                  uint256 tokenIdsIdx;
                                  address currOwnershipAddr;
                                  uint256 tokenIdsLength = balanceOf(owner);
                                  uint256[] memory tokenIds = new uint256[](tokenIdsLength);
                                  TokenOwnership memory ownership;
                                  for (uint256 i = _startTokenId(); tokenIdsIdx != tokenIdsLength; ++i) {
                                      ownership = _ownershipAt(i);
                                      if (ownership.burned) {
                                          continue;
                                      }
                                      if (ownership.addr != address(0)) {
                                          currOwnershipAddr = ownership.addr;
                                      }
                                      if (currOwnershipAddr == owner) {
                                          tokenIds[tokenIdsIdx++] = i;
                                      }
                                  }
                                  return tokenIds;
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // ERC721A Contracts v4.2.3
                      // Creator: Chiru Labs
                      pragma solidity ^0.8.4;
                      import '../IERC721AUpgradeable.sol';
                      /**
                       * @dev Interface of ERC721AQueryable.
                       */
                      interface IERC721AQueryableUpgradeable is IERC721AUpgradeable {
                          /**
                           * Invalid query range (`start` >= `stop`).
                           */
                          error InvalidQueryRange();
                          /**
                           * @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
                           *
                           * If the `tokenId` is out of bounds:
                           *
                           * - `addr = address(0)`
                           * - `startTimestamp = 0`
                           * - `burned = false`
                           * - `extraData = 0`
                           *
                           * If the `tokenId` is burned:
                           *
                           * - `addr = <Address of owner before token was burned>`
                           * - `startTimestamp = <Timestamp when token was burned>`
                           * - `burned = true`
                           * - `extraData = <Extra data when token was burned>`
                           *
                           * Otherwise:
                           *
                           * - `addr = <Address of owner>`
                           * - `startTimestamp = <Timestamp of start of ownership>`
                           * - `burned = false`
                           * - `extraData = <Extra data at start of ownership>`
                           */
                          function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory);
                          /**
                           * @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order.
                           * See {ERC721AQueryable-explicitOwnershipOf}
                           */
                          function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory);
                          /**
                           * @dev Returns an array of token IDs owned by `owner`,
                           * in the range [`start`, `stop`)
                           * (i.e. `start <= tokenId < stop`).
                           *
                           * This function allows for tokens to be queried if the collection
                           * grows too big for a single call of {ERC721AQueryable-tokensOfOwner}.
                           *
                           * Requirements:
                           *
                           * - `start < stop`
                           */
                          function tokensOfOwnerIn(
                              address owner,
                              uint256 start,
                              uint256 stop
                          ) external view returns (uint256[] memory);
                          /**
                           * @dev Returns an array of token IDs owned by `owner`.
                           *
                           * This function scans the ownership mapping and is O(`totalSupply`) in complexity.
                           * It is meant to be called off-chain.
                           *
                           * See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into
                           * multiple smaller scans if the collection is large enough to cause
                           * an out-of-gas error (10K collections should be fine).
                           */
                          function tokensOfOwner(address owner) external view returns (uint256[] memory);
                      }
                      // SPDX-License-Identifier: MIT
                      // ERC721A Contracts v4.2.3
                      // Creator: Chiru Labs
                      pragma solidity ^0.8.4;
                      /**
                       * @dev Interface of ERC721A.
                       */
                      interface IERC721AUpgradeable {
                          /**
                           * The caller must own the token or be an approved operator.
                           */
                          error ApprovalCallerNotOwnerNorApproved();
                          /**
                           * The token does not exist.
                           */
                          error ApprovalQueryForNonexistentToken();
                          /**
                           * Cannot query the balance for the zero address.
                           */
                          error BalanceQueryForZeroAddress();
                          /**
                           * Cannot mint to the zero address.
                           */
                          error MintToZeroAddress();
                          /**
                           * The quantity of tokens minted must be more than zero.
                           */
                          error MintZeroQuantity();
                          /**
                           * The token does not exist.
                           */
                          error OwnerQueryForNonexistentToken();
                          /**
                           * The caller must own the token or be an approved operator.
                           */
                          error TransferCallerNotOwnerNorApproved();
                          /**
                           * The token must be owned by `from`.
                           */
                          error TransferFromIncorrectOwner();
                          /**
                           * Cannot safely transfer to a contract that does not implement the
                           * ERC721Receiver interface.
                           */
                          error TransferToNonERC721ReceiverImplementer();
                          /**
                           * Cannot transfer to the zero address.
                           */
                          error TransferToZeroAddress();
                          /**
                           * The token does not exist.
                           */
                          error URIQueryForNonexistentToken();
                          /**
                           * The `quantity` minted with ERC2309 exceeds the safety limit.
                           */
                          error MintERC2309QuantityExceedsLimit();
                          /**
                           * The `extraData` cannot be set on an unintialized ownership slot.
                           */
                          error OwnershipNotInitializedForExtraData();
                          // =============================================================
                          //                            STRUCTS
                          // =============================================================
                          struct TokenOwnership {
                              // The address of the owner.
                              address addr;
                              // Stores the start time of ownership with minimal overhead for tokenomics.
                              uint64 startTimestamp;
                              // Whether the token has been burned.
                              bool burned;
                              // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
                              uint24 extraData;
                          }
                          // =============================================================
                          //                         TOKEN COUNTERS
                          // =============================================================
                          /**
                           * @dev Returns the total number of tokens in existence.
                           * Burned tokens will reduce the count.
                           * To get the total number of tokens minted, please see {_totalMinted}.
                           */
                          function totalSupply() external view returns (uint256);
                          // =============================================================
                          //                            IERC165
                          // =============================================================
                          /**
                           * @dev Returns true if this contract implements the interface defined by
                           * `interfaceId`. See the corresponding
                           * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
                           * to learn more about how these ids are created.
                           *
                           * This function call must use less than 30000 gas.
                           */
                          function supportsInterface(bytes4 interfaceId) external view returns (bool);
                          // =============================================================
                          //                            IERC721
                          // =============================================================
                          /**
                           * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
                           */
                          event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
                          /**
                           * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
                           */
                          event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
                          /**
                           * @dev Emitted when `owner` enables or disables
                           * (`approved`) `operator` to manage all of its assets.
                           */
                          event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
                          /**
                           * @dev Returns the number of tokens in `owner`'s account.
                           */
                          function balanceOf(address owner) external view returns (uint256 balance);
                          /**
                           * @dev Returns the owner of the `tokenId` token.
                           *
                           * Requirements:
                           *
                           * - `tokenId` must exist.
                           */
                          function ownerOf(uint256 tokenId) external view returns (address owner);
                          /**
                           * @dev Safely transfers `tokenId` token from `from` to `to`,
                           * checking first that contract recipients are aware of the ERC721 protocol
                           * to prevent tokens from being forever locked.
                           *
                           * Requirements:
                           *
                           * - `from` cannot be the zero address.
                           * - `to` cannot be the zero address.
                           * - `tokenId` token must exist and be owned by `from`.
                           * - If the caller is not `from`, it must be have been allowed to move
                           * this token by either {approve} or {setApprovalForAll}.
                           * - If `to` refers to a smart contract, it must implement
                           * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
                           *
                           * Emits a {Transfer} event.
                           */
                          function safeTransferFrom(
                              address from,
                              address to,
                              uint256 tokenId,
                              bytes calldata data
                          ) external payable;
                          /**
                           * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
                           */
                          function safeTransferFrom(
                              address from,
                              address to,
                              uint256 tokenId
                          ) external payable;
                          /**
                           * @dev Transfers `tokenId` from `from` to `to`.
                           *
                           * WARNING: Usage of this method is discouraged, use {safeTransferFrom}
                           * whenever possible.
                           *
                           * Requirements:
                           *
                           * - `from` cannot be the zero address.
                           * - `to` cannot be the zero address.
                           * - `tokenId` token must be owned by `from`.
                           * - If the caller is not `from`, it must be approved to move this token
                           * by either {approve} or {setApprovalForAll}.
                           *
                           * Emits a {Transfer} event.
                           */
                          function transferFrom(
                              address from,
                              address to,
                              uint256 tokenId
                          ) external payable;
                          /**
                           * @dev Gives permission to `to` to transfer `tokenId` token to another account.
                           * The approval is cleared when the token is transferred.
                           *
                           * Only a single account can be approved at a time, so approving the
                           * zero address clears previous approvals.
                           *
                           * Requirements:
                           *
                           * - The caller must own the token or be an approved operator.
                           * - `tokenId` must exist.
                           *
                           * Emits an {Approval} event.
                           */
                          function approve(address to, uint256 tokenId) external payable;
                          /**
                           * @dev Approve or remove `operator` as an operator for the caller.
                           * Operators can call {transferFrom} or {safeTransferFrom}
                           * for any token owned by the caller.
                           *
                           * Requirements:
                           *
                           * - The `operator` cannot be the caller.
                           *
                           * Emits an {ApprovalForAll} event.
                           */
                          function setApprovalForAll(address operator, bool _approved) external;
                          /**
                           * @dev Returns the account approved for `tokenId` token.
                           *
                           * Requirements:
                           *
                           * - `tokenId` must exist.
                           */
                          function getApproved(uint256 tokenId) external view returns (address operator);
                          /**
                           * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
                           *
                           * See {setApprovalForAll}.
                           */
                          function isApprovedForAll(address owner, address operator) external view returns (bool);
                          // =============================================================
                          //                        IERC721Metadata
                          // =============================================================
                          /**
                           * @dev Returns the token collection name.
                           */
                          function name() external view returns (string memory);
                          /**
                           * @dev Returns the token collection symbol.
                           */
                          function symbol() external view returns (string memory);
                          /**
                           * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
                           */
                          function tokenURI(uint256 tokenId) external view returns (string memory);
                          // =============================================================
                          //                           IERC2309
                          // =============================================================
                          /**
                           * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
                           * (inclusive) is transferred from `from` to `to`, as defined in the
                           * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
                           *
                           * See {_mintERC2309} for more details.
                           */
                          event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      abstract contract Proxied {
                          /// @notice to be used by initialisation / postUpgrade function so that only the proxy's admin can execute them
                          /// It also allows these functions to be called inside a contructor
                          /// even if the contract is meant to be used without proxy
                          modifier proxied() {
                              address proxyAdminAddress = _proxyAdmin();
                              // With hardhat-deploy proxies
                              // the proxyAdminAddress is zero only for the implementation contract
                              // if the implementation contract want to be used as a standalone/immutable contract
                              // it simply has to execute the `proxied` function
                              // This ensure the proxyAdminAddress is never zero post deployment
                              // And allow you to keep the same code for both proxied contract and immutable contract
                              if (proxyAdminAddress == address(0)) {
                                  // ensure can not be called twice when used outside of proxy : no admin
                                  // solhint-disable-next-line security/no-inline-assembly
                                  assembly {
                                      sstore(
                                          0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103,
                                          0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
                                      )
                                  }
                              } else {
                                  require(msg.sender == proxyAdminAddress);
                              }
                              _;
                          }
                          modifier onlyProxyAdmin() {
                              require(msg.sender == _proxyAdmin(), "NOT_AUTHORIZED");
                              _;
                          }
                          function _proxyAdmin() internal view returns (address ownerAddress) {
                              // solhint-disable-next-line security/no-inline-assembly
                              assembly {
                                  ownerAddress := sload(0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103)
                              }
                          }
                      }
                      

                      File 5 of 6: OperatorFilterRegistry
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
                      pragma solidity ^0.8.0;
                      import "../utils/Context.sol";
                      /**
                       * @dev Contract module which provides a basic access control mechanism, where
                       * there is an account (an owner) that can be granted exclusive access to
                       * specific functions.
                       *
                       * By default, the owner account will be the one that deploys the contract. This
                       * can later be changed with {transferOwnership}.
                       *
                       * This module is used through inheritance. It will make available the modifier
                       * `onlyOwner`, which can be applied to your functions to restrict their use to
                       * the owner.
                       */
                      abstract contract Ownable is Context {
                          address private _owner;
                          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                          /**
                           * @dev Initializes the contract setting the deployer as the initial owner.
                           */
                          constructor() {
                              _transferOwnership(_msgSender());
                          }
                          /**
                           * @dev Throws if called by any account other than the owner.
                           */
                          modifier onlyOwner() {
                              _checkOwner();
                              _;
                          }
                          /**
                           * @dev Returns the address of the current owner.
                           */
                          function owner() public view virtual returns (address) {
                              return _owner;
                          }
                          /**
                           * @dev Throws if the sender is not the owner.
                           */
                          function _checkOwner() internal view virtual {
                              require(owner() == _msgSender(), "Ownable: caller is not the owner");
                          }
                          /**
                           * @dev Leaves the contract without owner. It will not be possible to call
                           * `onlyOwner` functions anymore. Can only be called by the current owner.
                           *
                           * NOTE: Renouncing ownership will leave the contract without an owner,
                           * thereby removing any functionality that is only available to the owner.
                           */
                          function renounceOwnership() public virtual onlyOwner {
                              _transferOwnership(address(0));
                          }
                          /**
                           * @dev Transfers ownership of the contract to a new account (`newOwner`).
                           * Can only be called by the current owner.
                           */
                          function transferOwnership(address newOwner) public virtual onlyOwner {
                              require(newOwner != address(0), "Ownable: new owner is the zero address");
                              _transferOwnership(newOwner);
                          }
                          /**
                           * @dev Transfers ownership of the contract to a new account (`newOwner`).
                           * Internal function without access restriction.
                           */
                          function _transferOwnership(address newOwner) internal virtual {
                              address oldOwner = _owner;
                              _owner = newOwner;
                              emit OwnershipTransferred(oldOwner, newOwner);
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev Provides information about the current execution context, including the
                       * sender of the transaction and its data. While these are generally available
                       * via msg.sender and msg.data, they should not be accessed in such a direct
                       * manner, since when dealing with meta-transactions the account sending and
                       * paying for execution may not be the actual sender (as far as an application
                       * is concerned).
                       *
                       * This contract is only required for intermediate, library-like contracts.
                       */
                      abstract contract Context {
                          function _msgSender() internal view virtual returns (address) {
                              return msg.sender;
                          }
                          function _msgData() internal view virtual returns (bytes calldata) {
                              return msg.data;
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
                      // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
                      pragma solidity ^0.8.0;
                      /**
                       * @dev Library for managing
                       * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
                       * types.
                       *
                       * Sets have the following properties:
                       *
                       * - Elements are added, removed, and checked for existence in constant time
                       * (O(1)).
                       * - Elements are enumerated in O(n). No guarantees are made on the ordering.
                       *
                       * ```
                       * contract Example {
                       *     // Add the library methods
                       *     using EnumerableSet for EnumerableSet.AddressSet;
                       *
                       *     // Declare a set state variable
                       *     EnumerableSet.AddressSet private mySet;
                       * }
                       * ```
                       *
                       * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
                       * and `uint256` (`UintSet`) are supported.
                       *
                       * [WARNING]
                       * ====
                       * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
                       * unusable.
                       * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
                       *
                       * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
                       * array of EnumerableSet.
                       * ====
                       */
                      library EnumerableSet {
                          // To implement this library for multiple types with as little code
                          // repetition as possible, we write it in terms of a generic Set type with
                          // bytes32 values.
                          // The Set implementation uses private functions, and user-facing
                          // implementations (such as AddressSet) are just wrappers around the
                          // underlying Set.
                          // This means that we can only create new EnumerableSets for types that fit
                          // in bytes32.
                          struct Set {
                              // Storage of set values
                              bytes32[] _values;
                              // Position of the value in the `values` array, plus 1 because index 0
                              // means a value is not in the set.
                              mapping(bytes32 => uint256) _indexes;
                          }
                          /**
                           * @dev Add a value to a set. O(1).
                           *
                           * Returns true if the value was added to the set, that is if it was not
                           * already present.
                           */
                          function _add(Set storage set, bytes32 value) private returns (bool) {
                              if (!_contains(set, value)) {
                                  set._values.push(value);
                                  // The value is stored at length-1, but we add 1 to all indexes
                                  // and use 0 as a sentinel value
                                  set._indexes[value] = set._values.length;
                                  return true;
                              } else {
                                  return false;
                              }
                          }
                          /**
                           * @dev Removes a value from a set. O(1).
                           *
                           * Returns true if the value was removed from the set, that is if it was
                           * present.
                           */
                          function _remove(Set storage set, bytes32 value) private returns (bool) {
                              // We read and store the value's index to prevent multiple reads from the same storage slot
                              uint256 valueIndex = set._indexes[value];
                              if (valueIndex != 0) {
                                  // Equivalent to contains(set, value)
                                  // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                                  // the array, and then remove the last element (sometimes called as 'swap and pop').
                                  // This modifies the order of the array, as noted in {at}.
                                  uint256 toDeleteIndex = valueIndex - 1;
                                  uint256 lastIndex = set._values.length - 1;
                                  if (lastIndex != toDeleteIndex) {
                                      bytes32 lastValue = set._values[lastIndex];
                                      // Move the last value to the index where the value to delete is
                                      set._values[toDeleteIndex] = lastValue;
                                      // Update the index for the moved value
                                      set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
                                  }
                                  // Delete the slot where the moved value was stored
                                  set._values.pop();
                                  // Delete the index for the deleted slot
                                  delete set._indexes[value];
                                  return true;
                              } else {
                                  return false;
                              }
                          }
                          /**
                           * @dev Returns true if the value is in the set. O(1).
                           */
                          function _contains(Set storage set, bytes32 value) private view returns (bool) {
                              return set._indexes[value] != 0;
                          }
                          /**
                           * @dev Returns the number of values on the set. O(1).
                           */
                          function _length(Set storage set) private view returns (uint256) {
                              return set._values.length;
                          }
                          /**
                           * @dev Returns the value stored at position `index` in the set. O(1).
                           *
                           * Note that there are no guarantees on the ordering of values inside the
                           * array, and it may change when more values are added or removed.
                           *
                           * Requirements:
                           *
                           * - `index` must be strictly less than {length}.
                           */
                          function _at(Set storage set, uint256 index) private view returns (bytes32) {
                              return set._values[index];
                          }
                          /**
                           * @dev Return the entire set in an array
                           *
                           * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                           * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                           * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                           * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                           */
                          function _values(Set storage set) private view returns (bytes32[] memory) {
                              return set._values;
                          }
                          // Bytes32Set
                          struct Bytes32Set {
                              Set _inner;
                          }
                          /**
                           * @dev Add a value to a set. O(1).
                           *
                           * Returns true if the value was added to the set, that is if it was not
                           * already present.
                           */
                          function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
                              return _add(set._inner, value);
                          }
                          /**
                           * @dev Removes a value from a set. O(1).
                           *
                           * Returns true if the value was removed from the set, that is if it was
                           * present.
                           */
                          function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
                              return _remove(set._inner, value);
                          }
                          /**
                           * @dev Returns true if the value is in the set. O(1).
                           */
                          function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
                              return _contains(set._inner, value);
                          }
                          /**
                           * @dev Returns the number of values in the set. O(1).
                           */
                          function length(Bytes32Set storage set) internal view returns (uint256) {
                              return _length(set._inner);
                          }
                          /**
                           * @dev Returns the value stored at position `index` in the set. O(1).
                           *
                           * Note that there are no guarantees on the ordering of values inside the
                           * array, and it may change when more values are added or removed.
                           *
                           * Requirements:
                           *
                           * - `index` must be strictly less than {length}.
                           */
                          function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
                              return _at(set._inner, index);
                          }
                          /**
                           * @dev Return the entire set in an array
                           *
                           * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                           * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                           * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                           * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                           */
                          function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
                              bytes32[] memory store = _values(set._inner);
                              bytes32[] memory result;
                              /// @solidity memory-safe-assembly
                              assembly {
                                  result := store
                              }
                              return result;
                          }
                          // AddressSet
                          struct AddressSet {
                              Set _inner;
                          }
                          /**
                           * @dev Add a value to a set. O(1).
                           *
                           * Returns true if the value was added to the set, that is if it was not
                           * already present.
                           */
                          function add(AddressSet storage set, address value) internal returns (bool) {
                              return _add(set._inner, bytes32(uint256(uint160(value))));
                          }
                          /**
                           * @dev Removes a value from a set. O(1).
                           *
                           * Returns true if the value was removed from the set, that is if it was
                           * present.
                           */
                          function remove(AddressSet storage set, address value) internal returns (bool) {
                              return _remove(set._inner, bytes32(uint256(uint160(value))));
                          }
                          /**
                           * @dev Returns true if the value is in the set. O(1).
                           */
                          function contains(AddressSet storage set, address value) internal view returns (bool) {
                              return _contains(set._inner, bytes32(uint256(uint160(value))));
                          }
                          /**
                           * @dev Returns the number of values in the set. O(1).
                           */
                          function length(AddressSet storage set) internal view returns (uint256) {
                              return _length(set._inner);
                          }
                          /**
                           * @dev Returns the value stored at position `index` in the set. O(1).
                           *
                           * Note that there are no guarantees on the ordering of values inside the
                           * array, and it may change when more values are added or removed.
                           *
                           * Requirements:
                           *
                           * - `index` must be strictly less than {length}.
                           */
                          function at(AddressSet storage set, uint256 index) internal view returns (address) {
                              return address(uint160(uint256(_at(set._inner, index))));
                          }
                          /**
                           * @dev Return the entire set in an array
                           *
                           * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                           * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                           * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                           * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                           */
                          function values(AddressSet storage set) internal view returns (address[] memory) {
                              bytes32[] memory store = _values(set._inner);
                              address[] memory result;
                              /// @solidity memory-safe-assembly
                              assembly {
                                  result := store
                              }
                              return result;
                          }
                          // UintSet
                          struct UintSet {
                              Set _inner;
                          }
                          /**
                           * @dev Add a value to a set. O(1).
                           *
                           * Returns true if the value was added to the set, that is if it was not
                           * already present.
                           */
                          function add(UintSet storage set, uint256 value) internal returns (bool) {
                              return _add(set._inner, bytes32(value));
                          }
                          /**
                           * @dev Removes a value from a set. O(1).
                           *
                           * Returns true if the value was removed from the set, that is if it was
                           * present.
                           */
                          function remove(UintSet storage set, uint256 value) internal returns (bool) {
                              return _remove(set._inner, bytes32(value));
                          }
                          /**
                           * @dev Returns true if the value is in the set. O(1).
                           */
                          function contains(UintSet storage set, uint256 value) internal view returns (bool) {
                              return _contains(set._inner, bytes32(value));
                          }
                          /**
                           * @dev Returns the number of values in the set. O(1).
                           */
                          function length(UintSet storage set) internal view returns (uint256) {
                              return _length(set._inner);
                          }
                          /**
                           * @dev Returns the value stored at position `index` in the set. O(1).
                           *
                           * Note that there are no guarantees on the ordering of values inside the
                           * array, and it may change when more values are added or removed.
                           *
                           * Requirements:
                           *
                           * - `index` must be strictly less than {length}.
                           */
                          function at(UintSet storage set, uint256 index) internal view returns (uint256) {
                              return uint256(_at(set._inner, index));
                          }
                          /**
                           * @dev Return the entire set in an array
                           *
                           * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                           * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                           * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                           * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                           */
                          function values(UintSet storage set) internal view returns (uint256[] memory) {
                              bytes32[] memory store = _values(set._inner);
                              uint256[] memory result;
                              /// @solidity memory-safe-assembly
                              assembly {
                                  result := store
                              }
                              return result;
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.13;
                      import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol";
                      interface IOperatorFilterRegistry {
                          function isOperatorAllowed(address registrant, address operator) external returns (bool);
                          function register(address registrant) external;
                          function registerAndSubscribe(address registrant, address subscription) external;
                          function registerAndCopyEntries(address registrant, address registrantToCopy) external;
                          function updateOperator(address registrant, address operator, bool filtered) external;
                          function updateOperators(address registrant, address[] calldata operators, bool filtered) external;
                          function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external;
                          function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external;
                          function subscribe(address registrant, address registrantToSubscribe) external;
                          function unsubscribe(address registrant, bool copyExistingEntries) external;
                          function subscriptionOf(address addr) external returns (address registrant);
                          function subscribers(address registrant) external returns (address[] memory);
                          function subscriberAt(address registrant, uint256 index) external returns (address);
                          function copyEntriesOf(address registrant, address registrantToCopy) external;
                          function isOperatorFiltered(address registrant, address operator) external returns (bool);
                          function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool);
                          function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool);
                          function filteredOperators(address addr) external returns (address[] memory);
                          function filteredCodeHashes(address addr) external returns (bytes32[] memory);
                          function filteredOperatorAt(address registrant, uint256 index) external returns (address);
                          function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32);
                          function isRegistered(address addr) external returns (bool);
                          function codeHashOf(address addr) external returns (bytes32);
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.13;
                      import {IOperatorFilterRegistry} from "./IOperatorFilterRegistry.sol";
                      import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";
                      import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol";
                      import {OperatorFilterRegistryErrorsAndEvents} from "./OperatorFilterRegistryErrorsAndEvents.sol";
                      /**
                       * @title  OperatorFilterRegistry
                       * @notice Borrows heavily from the QQL BlacklistOperatorFilter contract:
                       *         https://github.com/qql-art/contracts/blob/main/contracts/BlacklistOperatorFilter.sol
                       * @notice This contracts allows tokens or token owners to register specific addresses or codeHashes that may be
                       * *       restricted according to the isOperatorAllowed function.
                       */
                      contract OperatorFilterRegistry is IOperatorFilterRegistry, OperatorFilterRegistryErrorsAndEvents {
                          using EnumerableSet for EnumerableSet.AddressSet;
                          using EnumerableSet for EnumerableSet.Bytes32Set;
                          /// @dev initialized accounts have a nonzero codehash (see https://eips.ethereum.org/EIPS/eip-1052)
                          /// Note that this will also be a smart contract's codehash when making calls from its constructor.
                          bytes32 constant EOA_CODEHASH = keccak256("");
                          mapping(address => EnumerableSet.AddressSet) private _filteredOperators;
                          mapping(address => EnumerableSet.Bytes32Set) private _filteredCodeHashes;
                          mapping(address => address) private _registrations;
                          mapping(address => EnumerableSet.AddressSet) private _subscribers;
                          /**
                           * @notice restricts method caller to the address or EIP-173 "owner()"
                           */
                          modifier onlyAddressOrOwner(address addr) {
                              if (msg.sender != addr) {
                                  try Ownable(addr).owner() returns (address owner) {
                                      if (msg.sender != owner) {
                                          revert OnlyAddressOrOwner();
                                      }
                                  } catch (bytes memory reason) {
                                      if (reason.length == 0) {
                                          revert NotOwnable();
                                      } else {
                                          /// @solidity memory-safe-assembly
                                          assembly {
                                              revert(add(32, reason), mload(reason))
                                          }
                                      }
                                  }
                              }
                              _;
                          }
                          /**
                           * @notice Returns true if operator is not filtered for a given token, either by address or codeHash. Also returns
                           *         true if supplied registrant address is not registered.
                           */
                          function isOperatorAllowed(address registrant, address operator) external view returns (bool) {
                              address registration = _registrations[registrant];
                              if (registration != address(0)) {
                                  EnumerableSet.AddressSet storage filteredOperatorsRef;
                                  EnumerableSet.Bytes32Set storage filteredCodeHashesRef;
                                  filteredOperatorsRef = _filteredOperators[registration];
                                  filteredCodeHashesRef = _filteredCodeHashes[registration];
                                  if (filteredOperatorsRef.contains(operator)) {
                                      revert AddressFiltered(operator);
                                  }
                                  if (operator.code.length > 0) {
                                      bytes32 codeHash = operator.codehash;
                                      if (filteredCodeHashesRef.contains(codeHash)) {
                                          revert CodeHashFiltered(operator, codeHash);
                                      }
                                  }
                              }
                              return true;
                          }
                          //////////////////
                          // AUTH METHODS //
                          //////////////////
                          /**
                           * @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner.
                           */
                          function register(address registrant) external onlyAddressOrOwner(registrant) {
                              if (_registrations[registrant] != address(0)) {
                                  revert AlreadyRegistered();
                              }
                              _registrations[registrant] = registrant;
                              emit RegistrationUpdated(registrant, true);
                          }
                          /**
                           * @notice Unregisters an address with the registry and removes its subscription. May be called by address itself or by EIP-173 owner.
                           *         Note that this does not remove any filtered addresses or codeHashes.
                           *         Also note that any subscriptions to this registrant will still be active and follow the existing filtered addresses and codehashes.
                           */
                          function unregister(address registrant) external onlyAddressOrOwner(registrant) {
                              address registration = _registrations[registrant];
                              if (registration == address(0)) {
                                  revert NotRegistered(registrant);
                              }
                              if (registration != registrant) {
                                  _subscribers[registration].remove(registrant);
                                  emit SubscriptionUpdated(registrant, registration, false);
                              }
                              _registrations[registrant] = address(0);
                              emit RegistrationUpdated(registrant, false);
                          }
                          /**
                           * @notice Registers an address with the registry and "subscribes" to another address's filtered operators and codeHashes.
                           */
                          function registerAndSubscribe(address registrant, address subscription) external onlyAddressOrOwner(registrant) {
                              address registration = _registrations[registrant];
                              if (registration != address(0)) {
                                  revert AlreadyRegistered();
                              }
                              if (registrant == subscription) {
                                  revert CannotSubscribeToSelf();
                              }
                              address subscriptionRegistration = _registrations[subscription];
                              if (subscriptionRegistration == address(0)) {
                                  revert NotRegistered(subscription);
                              }
                              if (subscriptionRegistration != subscription) {
                                  revert CannotSubscribeToRegistrantWithSubscription(subscription);
                              }
                              _registrations[registrant] = subscription;
                              _subscribers[subscription].add(registrant);
                              emit RegistrationUpdated(registrant, true);
                              emit SubscriptionUpdated(registrant, subscription, true);
                          }
                          /**
                           * @notice Registers an address with the registry and copies the filtered operators and codeHashes from another
                           *         address without subscribing.
                           */
                          function registerAndCopyEntries(address registrant, address registrantToCopy)
                              external
                              onlyAddressOrOwner(registrant)
                          {
                              if (registrantToCopy == registrant) {
                                  revert CannotCopyFromSelf();
                              }
                              address registration = _registrations[registrant];
                              if (registration != address(0)) {
                                  revert AlreadyRegistered();
                              }
                              address registrantRegistration = _registrations[registrantToCopy];
                              if (registrantRegistration == address(0)) {
                                  revert NotRegistered(registrantToCopy);
                              }
                              _registrations[registrant] = registrant;
                              emit RegistrationUpdated(registrant, true);
                              _copyEntries(registrant, registrantToCopy);
                          }
                          /**
                           * @notice Update an operator address for a registered address - when filtered is true, the operator is filtered.
                           */
                          function updateOperator(address registrant, address operator, bool filtered)
                              external
                              onlyAddressOrOwner(registrant)
                          {
                              address registration = _registrations[registrant];
                              if (registration == address(0)) {
                                  revert NotRegistered(registrant);
                              }
                              if (registration != registrant) {
                                  revert CannotUpdateWhileSubscribed(registration);
                              }
                              EnumerableSet.AddressSet storage filteredOperatorsRef = _filteredOperators[registrant];
                              if (!filtered) {
                                  bool removed = filteredOperatorsRef.remove(operator);
                                  if (!removed) {
                                      revert AddressNotFiltered(operator);
                                  }
                              } else {
                                  bool added = filteredOperatorsRef.add(operator);
                                  if (!added) {
                                      revert AddressAlreadyFiltered(operator);
                                  }
                              }
                              emit OperatorUpdated(registrant, operator, filtered);
                          }
                          /**
                           * @notice Update a codeHash for a registered address - when filtered is true, the codeHash is filtered.
                           */
                          function updateCodeHash(address registrant, bytes32 codeHash, bool filtered)
                              external
                              onlyAddressOrOwner(registrant)
                          {
                              if (codeHash == EOA_CODEHASH) {
                                  revert CannotFilterEOAs();
                              }
                              address registration = _registrations[registrant];
                              if (registration == address(0)) {
                                  revert NotRegistered(registrant);
                              }
                              if (registration != registrant) {
                                  revert CannotUpdateWhileSubscribed(registration);
                              }
                              EnumerableSet.Bytes32Set storage filteredCodeHashesRef = _filteredCodeHashes[registrant];
                              if (!filtered) {
                                  bool removed = filteredCodeHashesRef.remove(codeHash);
                                  if (!removed) {
                                      revert CodeHashNotFiltered(codeHash);
                                  }
                              } else {
                                  bool added = filteredCodeHashesRef.add(codeHash);
                                  if (!added) {
                                      revert CodeHashAlreadyFiltered(codeHash);
                                  }
                              }
                              emit CodeHashUpdated(registrant, codeHash, filtered);
                          }
                          /**
                           * @notice Update multiple operators for a registered address - when filtered is true, the operators will be filtered. Reverts on duplicates.
                           */
                          function updateOperators(address registrant, address[] calldata operators, bool filtered)
                              external
                              onlyAddressOrOwner(registrant)
                          {
                              address registration = _registrations[registrant];
                              if (registration == address(0)) {
                                  revert NotRegistered(registrant);
                              }
                              if (registration != registrant) {
                                  revert CannotUpdateWhileSubscribed(registration);
                              }
                              EnumerableSet.AddressSet storage filteredOperatorsRef = _filteredOperators[registrant];
                              uint256 operatorsLength = operators.length;
                              unchecked {
                                  if (!filtered) {
                                      for (uint256 i = 0; i < operatorsLength; ++i) {
                                          address operator = operators[i];
                                          bool removed = filteredOperatorsRef.remove(operator);
                                          if (!removed) {
                                              revert AddressNotFiltered(operator);
                                          }
                                      }
                                  } else {
                                      for (uint256 i = 0; i < operatorsLength; ++i) {
                                          address operator = operators[i];
                                          bool added = filteredOperatorsRef.add(operator);
                                          if (!added) {
                                              revert AddressAlreadyFiltered(operator);
                                          }
                                      }
                                  }
                              }
                              emit OperatorsUpdated(registrant, operators, filtered);
                          }
                          /**
                           * @notice Update multiple codeHashes for a registered address - when filtered is true, the codeHashes will be filtered. Reverts on duplicates.
                           */
                          function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered)
                              external
                              onlyAddressOrOwner(registrant)
                          {
                              address registration = _registrations[registrant];
                              if (registration == address(0)) {
                                  revert NotRegistered(registrant);
                              }
                              if (registration != registrant) {
                                  revert CannotUpdateWhileSubscribed(registration);
                              }
                              EnumerableSet.Bytes32Set storage filteredCodeHashesRef = _filteredCodeHashes[registrant];
                              uint256 codeHashesLength = codeHashes.length;
                              unchecked {
                                  if (!filtered) {
                                      for (uint256 i = 0; i < codeHashesLength; ++i) {
                                          bytes32 codeHash = codeHashes[i];
                                          bool removed = filteredCodeHashesRef.remove(codeHash);
                                          if (!removed) {
                                              revert CodeHashNotFiltered(codeHash);
                                          }
                                      }
                                  } else {
                                      for (uint256 i = 0; i < codeHashesLength; ++i) {
                                          bytes32 codeHash = codeHashes[i];
                                          if (codeHash == EOA_CODEHASH) {
                                              revert CannotFilterEOAs();
                                          }
                                          bool added = filteredCodeHashesRef.add(codeHash);
                                          if (!added) {
                                              revert CodeHashAlreadyFiltered(codeHash);
                                          }
                                      }
                                  }
                              }
                              emit CodeHashesUpdated(registrant, codeHashes, filtered);
                          }
                          /**
                           * @notice Subscribe an address to another registrant's filtered operators and codeHashes. Will remove previous
                           *         subscription if present.
                           *         Note that accounts with subscriptions may go on to subscribe to other accounts - in this case,
                           *         subscriptions will not be forwarded. Instead the former subscription's existing entries will still be
                           *         used.
                           */
                          function subscribe(address registrant, address newSubscription) external onlyAddressOrOwner(registrant) {
                              if (registrant == newSubscription) {
                                  revert CannotSubscribeToSelf();
                              }
                              if (newSubscription == address(0)) {
                                  revert CannotSubscribeToZeroAddress();
                              }
                              address registration = _registrations[registrant];
                              if (registration == address(0)) {
                                  revert NotRegistered(registrant);
                              }
                              if (registration == newSubscription) {
                                  revert AlreadySubscribed(newSubscription);
                              }
                              address newSubscriptionRegistration = _registrations[newSubscription];
                              if (newSubscriptionRegistration == address(0)) {
                                  revert NotRegistered(newSubscription);
                              }
                              if (newSubscriptionRegistration != newSubscription) {
                                  revert CannotSubscribeToRegistrantWithSubscription(newSubscription);
                              }
                              if (registration != registrant) {
                                  _subscribers[registration].remove(registrant);
                                  emit SubscriptionUpdated(registrant, registration, false);
                              }
                              _registrations[registrant] = newSubscription;
                              _subscribers[newSubscription].add(registrant);
                              emit SubscriptionUpdated(registrant, newSubscription, true);
                          }
                          /**
                           * @notice Unsubscribe an address from its current subscribed registrant, and optionally copy its filtered operators and codeHashes.
                           */
                          function unsubscribe(address registrant, bool copyExistingEntries) external onlyAddressOrOwner(registrant) {
                              address registration = _registrations[registrant];
                              if (registration == address(0)) {
                                  revert NotRegistered(registrant);
                              }
                              if (registration == registrant) {
                                  revert NotSubscribed();
                              }
                              _subscribers[registration].remove(registrant);
                              _registrations[registrant] = registrant;
                              emit SubscriptionUpdated(registrant, registration, false);
                              if (copyExistingEntries) {
                                  _copyEntries(registrant, registration);
                              }
                          }
                          /**
                           * @notice Copy filtered operators and codeHashes from a different registrantToCopy to addr.
                           */
                          function copyEntriesOf(address registrant, address registrantToCopy) external onlyAddressOrOwner(registrant) {
                              if (registrant == registrantToCopy) {
                                  revert CannotCopyFromSelf();
                              }
                              address registration = _registrations[registrant];
                              if (registration == address(0)) {
                                  revert NotRegistered(registrant);
                              }
                              if (registration != registrant) {
                                  revert CannotUpdateWhileSubscribed(registration);
                              }
                              address registrantRegistration = _registrations[registrantToCopy];
                              if (registrantRegistration == address(0)) {
                                  revert NotRegistered(registrantToCopy);
                              }
                              _copyEntries(registrant, registrantToCopy);
                          }
                          /// @dev helper to copy entries from registrantToCopy to registrant and emit events
                          function _copyEntries(address registrant, address registrantToCopy) private {
                              EnumerableSet.AddressSet storage filteredOperatorsRef = _filteredOperators[registrantToCopy];
                              EnumerableSet.Bytes32Set storage filteredCodeHashesRef = _filteredCodeHashes[registrantToCopy];
                              uint256 filteredOperatorsLength = filteredOperatorsRef.length();
                              uint256 filteredCodeHashesLength = filteredCodeHashesRef.length();
                              unchecked {
                                  for (uint256 i = 0; i < filteredOperatorsLength; ++i) {
                                      address operator = filteredOperatorsRef.at(i);
                                      bool added = _filteredOperators[registrant].add(operator);
                                      if (added) {
                                          emit OperatorUpdated(registrant, operator, true);
                                      }
                                  }
                                  for (uint256 i = 0; i < filteredCodeHashesLength; ++i) {
                                      bytes32 codehash = filteredCodeHashesRef.at(i);
                                      bool added = _filteredCodeHashes[registrant].add(codehash);
                                      if (added) {
                                          emit CodeHashUpdated(registrant, codehash, true);
                                      }
                                  }
                              }
                          }
                          //////////////////
                          // VIEW METHODS //
                          //////////////////
                          /**
                           * @notice Get the subscription address of a given registrant, if any.
                           */
                          function subscriptionOf(address registrant) external view returns (address subscription) {
                              subscription = _registrations[registrant];
                              if (subscription == address(0)) {
                                  revert NotRegistered(registrant);
                              } else if (subscription == registrant) {
                                  subscription = address(0);
                              }
                          }
                          /**
                           * @notice Get the set of addresses subscribed to a given registrant.
                           *         Note that order is not guaranteed as updates are made.
                           */
                          function subscribers(address registrant) external view returns (address[] memory) {
                              return _subscribers[registrant].values();
                          }
                          /**
                           * @notice Get the subscriber at a given index in the set of addresses subscribed to a given registrant.
                           *         Note that order is not guaranteed as updates are made.
                           */
                          function subscriberAt(address registrant, uint256 index) external view returns (address) {
                              return _subscribers[registrant].at(index);
                          }
                          /**
                           * @notice Returns true if operator is filtered by a given address or its subscription.
                           */
                          function isOperatorFiltered(address registrant, address operator) external view returns (bool) {
                              address registration = _registrations[registrant];
                              if (registration != registrant) {
                                  return _filteredOperators[registration].contains(operator);
                              }
                              return _filteredOperators[registrant].contains(operator);
                          }
                          /**
                           * @notice Returns true if a codeHash is filtered by a given address or its subscription.
                           */
                          function isCodeHashFiltered(address registrant, bytes32 codeHash) external view returns (bool) {
                              address registration = _registrations[registrant];
                              if (registration != registrant) {
                                  return _filteredCodeHashes[registration].contains(codeHash);
                              }
                              return _filteredCodeHashes[registrant].contains(codeHash);
                          }
                          /**
                           * @notice Returns true if the hash of an address's code is filtered by a given address or its subscription.
                           */
                          function isCodeHashOfFiltered(address registrant, address operatorWithCode) external view returns (bool) {
                              bytes32 codeHash = operatorWithCode.codehash;
                              address registration = _registrations[registrant];
                              if (registration != registrant) {
                                  return _filteredCodeHashes[registration].contains(codeHash);
                              }
                              return _filteredCodeHashes[registrant].contains(codeHash);
                          }
                          /**
                           * @notice Returns true if an address has registered
                           */
                          function isRegistered(address registrant) external view returns (bool) {
                              return _registrations[registrant] != address(0);
                          }
                          /**
                           * @notice Returns a list of filtered operators for a given address or its subscription.
                           */
                          function filteredOperators(address registrant) external view returns (address[] memory) {
                              address registration = _registrations[registrant];
                              if (registration != registrant) {
                                  return _filteredOperators[registration].values();
                              }
                              return _filteredOperators[registrant].values();
                          }
                          /**
                           * @notice Returns the set of filtered codeHashes for a given address or its subscription.
                           *         Note that order is not guaranteed as updates are made.
                           */
                          function filteredCodeHashes(address registrant) external view returns (bytes32[] memory) {
                              address registration = _registrations[registrant];
                              if (registration != registrant) {
                                  return _filteredCodeHashes[registration].values();
                              }
                              return _filteredCodeHashes[registrant].values();
                          }
                          /**
                           * @notice Returns the filtered operator at the given index of the set of filtered operators for a given address or
                           *         its subscription.
                           *         Note that order is not guaranteed as updates are made.
                           */
                          function filteredOperatorAt(address registrant, uint256 index) external view returns (address) {
                              address registration = _registrations[registrant];
                              if (registration != registrant) {
                                  return _filteredOperators[registration].at(index);
                              }
                              return _filteredOperators[registrant].at(index);
                          }
                          /**
                           * @notice Returns the filtered codeHash at the given index of the list of filtered codeHashes for a given address or
                           *         its subscription.
                           *         Note that order is not guaranteed as updates are made.
                           */
                          function filteredCodeHashAt(address registrant, uint256 index) external view returns (bytes32) {
                              address registration = _registrations[registrant];
                              if (registration != registrant) {
                                  return _filteredCodeHashes[registration].at(index);
                              }
                              return _filteredCodeHashes[registrant].at(index);
                          }
                          /// @dev Convenience method to compute the code hash of an arbitrary contract
                          function codeHashOf(address a) external view returns (bytes32) {
                              return a.codehash;
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.13;
                      contract OperatorFilterRegistryErrorsAndEvents {
                          error CannotFilterEOAs();
                          error AddressAlreadyFiltered(address operator);
                          error AddressNotFiltered(address operator);
                          error CodeHashAlreadyFiltered(bytes32 codeHash);
                          error CodeHashNotFiltered(bytes32 codeHash);
                          error OnlyAddressOrOwner();
                          error NotRegistered(address registrant);
                          error AlreadyRegistered();
                          error AlreadySubscribed(address subscription);
                          error NotSubscribed();
                          error CannotUpdateWhileSubscribed(address subscription);
                          error CannotSubscribeToSelf();
                          error CannotSubscribeToZeroAddress();
                          error NotOwnable();
                          error AddressFiltered(address filtered);
                          error CodeHashFiltered(address account, bytes32 codeHash);
                          error CannotSubscribeToRegistrantWithSubscription(address registrant);
                          error CannotCopyFromSelf();
                          event RegistrationUpdated(address indexed registrant, bool indexed registered);
                          event OperatorUpdated(address indexed registrant, address indexed operator, bool indexed filtered);
                          event OperatorsUpdated(address indexed registrant, address[] operators, bool indexed filtered);
                          event CodeHashUpdated(address indexed registrant, bytes32 indexed codeHash, bool indexed filtered);
                          event CodeHashesUpdated(address indexed registrant, bytes32[] codeHashes, bool indexed filtered);
                          event SubscriptionUpdated(address indexed registrant, address indexed subscription, bool indexed subscribed);
                      }
                      

                      File 6 of 6: BlurPool
                      // SPDX-License-Identifier: MIT
                      pragma solidity 0.8.17;
                      import "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
                      import "lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol";
                      import "./interfaces/IBlurPool.sol";
                      /**
                       * @title BlurPool
                       * @dev ETH pool; funds can only be transferred by Exchange, ExchangeV2, Swap or Blend
                       */
                      contract BlurPool is IBlurPool, OwnableUpgradeable, UUPSUpgradeable {
                          address private immutable EXCHANGE;
                          address private immutable EXCHANGE_V2;
                          address private immutable SWAP;
                          address private immutable BLEND;
                          mapping(address => uint256) private _balances;
                          string public constant name = 'Blur Pool';
                          string constant symbol = '';
                          // required by the OZ UUPS module
                          function _authorizeUpgrade(address) internal override onlyOwner {}
                          constructor(address exchange, address exchangeV2, address swap, address blend) {
                              _disableInitializers();
                              EXCHANGE = exchange;
                              EXCHANGE_V2 = exchangeV2;
                              SWAP = swap;
                              BLEND = blend;
                          }
                          /* Constructor (for ERC1967) */
                          function initialize() external initializer {
                              __Ownable_init();
                          }
                          function decimals() external pure returns (uint8) {
                              return 18;
                          }
                          function totalSupply() external view returns (uint256) {
                              return address(this).balance;
                          }
                          function balanceOf(address user) external view returns (uint256) {
                              return _balances[user];
                          }
                          /**
                           * @dev receive deposit function
                           */
                          receive() external payable {
                              deposit();
                          }
                          /**
                           * @dev deposit ETH into pool
                           */
                          function deposit() public payable {
                              _balances[msg.sender] += msg.value;
                              emit Transfer(address(0), msg.sender, msg.value);
                          }
                          /**
                           * @dev deposit ETH into pool on behalf of user
                           * @param user Address to deposit to
                           */
                          function deposit(address user) public payable {
                              if (msg.sender != BLEND && msg.sender != EXCHANGE_V2) {
                                  revert('Unauthorized deposit');
                              }
                              _balances[user] += msg.value;
                              emit Transfer(address(0), user, msg.value);
                          }
                          /**
                           * @dev withdraw ETH from pool
                           * @param amount Amount to withdraw
                           */
                          function withdraw(uint256 amount) external {
                              uint256 balance = _balances[msg.sender];
                              require(balance >= amount, "Insufficient funds");
                              unchecked {
                                  _balances[msg.sender] = balance - amount;
                              }
                              (bool success,) = payable(msg.sender).call{value: amount}("");
                              require(success, "Transfer failed");
                              emit Transfer(msg.sender, address(0), amount);
                          }
                          /**
                           * @dev withdraw ETH from pool on behalf of user; only callable by Blend
                           * @param from Address to withdraw from
                           * @param to Address to withdraw to
                           * @param amount Amount to withdraw
                           */
                          function withdrawFrom(address from, address to, uint256 amount) external {
                              if (msg.sender != BLEND && msg.sender != EXCHANGE_V2) {
                                  revert('Unauthorized transfer');
                              }
                              uint256 balance = _balances[from];
                              require(balance >= amount, "Insufficient balance");
                              unchecked {
                                  _balances[from] = balance - amount;
                              }
                              (bool success,) = payable(to).call{value: amount}("");
                              require(success, "Transfer failed");
                              emit Transfer(from, address(0), amount);
                          }
                          /**
                           * @dev transferFrom Transfer balances within pool; only callable by Swap, Exchange, and Blend
                           * @param from Pool fund sender
                           * @param to Pool fund recipient
                           * @param amount Amount to transfer
                           */
                          function transferFrom(address from, address to, uint256 amount)
                              external
                              returns (bool)
                          {
                              if (
                                  msg.sender != EXCHANGE &&
                                  msg.sender != EXCHANGE_V2 &&
                                  msg.sender != SWAP &&
                                  msg.sender != BLEND
                              ) {
                                  revert('Unauthorized transfer');
                              }
                              _transfer(from, to, amount);
                              return true;
                          }
                          function _transfer(address from, address to, uint256 amount) private {
                              require(to != address(0), "Cannot transfer to 0 address");
                              uint256 balance = _balances[from];
                              require(balance >= amount, "Insufficient balance");
                              unchecked {
                                  _balances[from] = balance - amount;
                              }
                              _balances[to] += amount;
                              emit Transfer(from, to, amount);
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)
                      pragma solidity ^0.8.0;
                      import "../../interfaces/draft-IERC1822Upgradeable.sol";
                      import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
                      import "./Initializable.sol";
                      /**
                       * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
                       * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
                       *
                       * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
                       * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
                       * `UUPSUpgradeable` with a custom implementation of upgrades.
                       *
                       * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
                       *
                       * _Available since v4.1._
                       */
                      abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
                          function __UUPSUpgradeable_init() internal onlyInitializing {
                          }
                          function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
                          }
                          /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
                          address private immutable __self = address(this);
                          /**
                           * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
                           * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
                           * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
                           * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
                           * fail.
                           */
                          modifier onlyProxy() {
                              require(address(this) != __self, "Function must be called through delegatecall");
                              require(_getImplementation() == __self, "Function must be called through active proxy");
                              _;
                          }
                          /**
                           * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
                           * callable on the implementing contract but not through proxies.
                           */
                          modifier notDelegated() {
                              require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
                              _;
                          }
                          /**
                           * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
                           * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                           *
                           * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                           * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                           * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
                           */
                          function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
                              return _IMPLEMENTATION_SLOT;
                          }
                          /**
                           * @dev Upgrade the implementation of the proxy to `newImplementation`.
                           *
                           * Calls {_authorizeUpgrade}.
                           *
                           * Emits an {Upgraded} event.
                           */
                          function upgradeTo(address newImplementation) external virtual onlyProxy {
                              _authorizeUpgrade(newImplementation);
                              _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
                          }
                          /**
                           * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                           * encoded in `data`.
                           *
                           * Calls {_authorizeUpgrade}.
                           *
                           * Emits an {Upgraded} event.
                           */
                          function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
                              _authorizeUpgrade(newImplementation);
                              _upgradeToAndCallUUPS(newImplementation, data, true);
                          }
                          /**
                           * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                           * {upgradeTo} and {upgradeToAndCall}.
                           *
                           * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                           *
                           * ```solidity
                           * function _authorizeUpgrade(address) internal override onlyOwner {}
                           * ```
                           */
                          function _authorizeUpgrade(address newImplementation) internal virtual;
                          /**
                           * @dev This empty reserved space is put in place to allow future versions to add new
                           * variables without shifting down storage in the inheritance chain.
                           * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                           */
                          uint256[50] private __gap;
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
                      pragma solidity ^0.8.0;
                      import "../utils/ContextUpgradeable.sol";
                      import "../proxy/utils/Initializable.sol";
                      /**
                       * @dev Contract module which provides a basic access control mechanism, where
                       * there is an account (an owner) that can be granted exclusive access to
                       * specific functions.
                       *
                       * By default, the owner account will be the one that deploys the contract. This
                       * can later be changed with {transferOwnership}.
                       *
                       * This module is used through inheritance. It will make available the modifier
                       * `onlyOwner`, which can be applied to your functions to restrict their use to
                       * the owner.
                       */
                      abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
                          address private _owner;
                          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                          /**
                           * @dev Initializes the contract setting the deployer as the initial owner.
                           */
                          function __Ownable_init() internal onlyInitializing {
                              __Ownable_init_unchained();
                          }
                          function __Ownable_init_unchained() internal onlyInitializing {
                              _transferOwnership(_msgSender());
                          }
                          /**
                           * @dev Throws if called by any account other than the owner.
                           */
                          modifier onlyOwner() {
                              _checkOwner();
                              _;
                          }
                          /**
                           * @dev Returns the address of the current owner.
                           */
                          function owner() public view virtual returns (address) {
                              return _owner;
                          }
                          /**
                           * @dev Throws if the sender is not the owner.
                           */
                          function _checkOwner() internal view virtual {
                              require(owner() == _msgSender(), "Ownable: caller is not the owner");
                          }
                          /**
                           * @dev Leaves the contract without owner. It will not be possible to call
                           * `onlyOwner` functions 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);
                          }
                          /**
                           * @dev This empty reserved space is put in place to allow future versions to add new
                           * variables without shifting down storage in the inheritance chain.
                           * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                           */
                          uint256[49] private __gap;
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      interface IBlurPool {
                          event Transfer(address indexed from, address indexed to, uint256 amount);
                          function initialize() external;
                          function decimals() external pure returns (uint8);
                          function totalSupply() external view returns (uint256);
                          function balanceOf(address user) external view returns (uint256);
                          function deposit() external payable;
                          function deposit(address user) external payable;
                          function withdraw(uint256 amount) external;
                          function withdrawFrom(address from, address to, uint256 amount) external;
                          function transferFrom(address from, address to, uint256 amount) external returns (bool);
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
                       * proxy whose upgrades are fully controlled by the current implementation.
                       */
                      interface IERC1822ProxiableUpgradeable {
                          /**
                           * @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.8.3) (proxy/ERC1967/ERC1967Upgrade.sol)
                      pragma solidity ^0.8.2;
                      import "../beacon/IBeaconUpgradeable.sol";
                      import "../../interfaces/IERC1967Upgradeable.sol";
                      import "../../interfaces/draft-IERC1822Upgradeable.sol";
                      import "../../utils/AddressUpgradeable.sol";
                      import "../../utils/StorageSlotUpgradeable.sol";
                      import "../utils/Initializable.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 ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable {
                          function __ERC1967Upgrade_init() internal onlyInitializing {
                          }
                          function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
                          }
                          // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                          bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                          /**
                           * @dev Storage slot with the address of the current implementation.
                           * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                           * validated in the constructor.
                           */
                          bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                          /**
                           * @dev Returns the current implementation address.
                           */
                          function _getImplementation() internal view returns (address) {
                              return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                          }
                          /**
                           * @dev Stores a new address in the EIP1967 implementation slot.
                           */
                          function _setImplementation(address newImplementation) private {
                              require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                              StorageSlotUpgradeable.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) {
                                  _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 (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
                                  _setImplementation(newImplementation);
                              } else {
                                  try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                                      require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                                  } catch {
                                      revert("ERC1967Upgrade: new implementation is not UUPS");
                                  }
                                  _upgradeToAndCall(newImplementation, data, forceCall);
                              }
                          }
                          /**
                           * @dev Storage slot with the admin of the contract.
                           * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                           * validated in the constructor.
                           */
                          bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                          /**
                           * @dev Returns the current admin.
                           */
                          function _getAdmin() internal view returns (address) {
                              return StorageSlotUpgradeable.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");
                              StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                          }
                          /**
                           * @dev Changes the admin of the proxy.
                           *
                           * Emits an {AdminChanged} event.
                           */
                          function _changeAdmin(address newAdmin) internal {
                              emit AdminChanged(_getAdmin(), newAdmin);
                              _setAdmin(newAdmin);
                          }
                          /**
                           * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                           * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                           */
                          bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                          /**
                           * @dev Returns the current beacon.
                           */
                          function _getBeacon() internal view returns (address) {
                              return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
                          }
                          /**
                           * @dev Stores a new beacon in the EIP1967 beacon slot.
                           */
                          function _setBeacon(address newBeacon) private {
                              require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                              require(
                                  AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
                                  "ERC1967: beacon implementation is not a contract"
                              );
                              StorageSlotUpgradeable.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) {
                                  _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
                              }
                          }
                          /**
                           * @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) private returns (bytes memory) {
                              require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");
                              // solhint-disable-next-line avoid-low-level-calls
                              (bool success, bytes memory returndata) = target.delegatecall(data);
                              return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
                          }
                          /**
                           * @dev This empty reserved space is put in place to allow future versions to add new
                           * variables without shifting down storage in the inheritance chain.
                           * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
                           */
                          uint256[50] private __gap;
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)
                      pragma solidity ^0.8.2;
                      import "../../utils/AddressUpgradeable.sol";
                      /**
                       * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
                       * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
                       * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
                       * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
                       *
                       * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
                       * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
                       * case an upgrade adds a module that needs to be initialized.
                       *
                       * For example:
                       *
                       * [.hljs-theme-light.nopadding]
                       * ```
                       * contract MyToken is ERC20Upgradeable {
                       *     function initialize() initializer public {
                       *         __ERC20_init("MyToken", "MTK");
                       *     }
                       * }
                       * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
                       *     function initializeV2() reinitializer(2) public {
                       *         __ERC20Permit_init("MyToken");
                       *     }
                       * }
                       * ```
                       *
                       * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
                       * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
                       *
                       * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
                       * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
                       *
                       * [CAUTION]
                       * ====
                       * Avoid leaving a contract uninitialized.
                       *
                       * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
                       * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
                       * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
                       *
                       * [.hljs-theme-light.nopadding]
                       * ```
                       * /// @custom:oz-upgrades-unsafe-allow constructor
                       * constructor() {
                       *     _disableInitializers();
                       * }
                       * ```
                       * ====
                       */
                      abstract contract Initializable {
                          /**
                           * @dev Indicates that the contract has been initialized.
                           * @custom:oz-retyped-from bool
                           */
                          uint8 private _initialized;
                          /**
                           * @dev Indicates that the contract is in the process of being initialized.
                           */
                          bool private _initializing;
                          /**
                           * @dev Triggered when the contract has been initialized or reinitialized.
                           */
                          event Initialized(uint8 version);
                          /**
                           * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                           * `onlyInitializing` functions can be used to initialize parent contracts.
                           *
                           * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
                           * constructor.
                           *
                           * Emits an {Initialized} event.
                           */
                          modifier initializer() {
                              bool isTopLevelCall = !_initializing;
                              require(
                                  (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                                  "Initializable: contract is already initialized"
                              );
                              _initialized = 1;
                              if (isTopLevelCall) {
                                  _initializing = true;
                              }
                              _;
                              if (isTopLevelCall) {
                                  _initializing = false;
                                  emit Initialized(1);
                              }
                          }
                          /**
                           * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                           * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                           * used to initialize parent contracts.
                           *
                           * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                           * are added through upgrades and that require initialization.
                           *
                           * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                           * cannot be nested. If one is invoked in the context of another, execution will revert.
                           *
                           * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                           * a contract, executing them in the right order is up to the developer or operator.
                           *
                           * WARNING: setting the version to 255 will prevent any future reinitialization.
                           *
                           * Emits an {Initialized} event.
                           */
                          modifier reinitializer(uint8 version) {
                              require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                              _initialized = version;
                              _initializing = true;
                              _;
                              _initializing = false;
                              emit Initialized(version);
                          }
                          /**
                           * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                           * {initializer} and {reinitializer} modifiers, directly or indirectly.
                           */
                          modifier onlyInitializing() {
                              require(_initializing, "Initializable: contract is not initializing");
                              _;
                          }
                          /**
                           * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                           * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                           * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                           * through proxies.
                           *
                           * Emits an {Initialized} event the first time it is successfully executed.
                           */
                          function _disableInitializers() internal virtual {
                              require(!_initializing, "Initializable: contract is initializing");
                              if (_initialized < type(uint8).max) {
                                  _initialized = type(uint8).max;
                                  emit Initialized(type(uint8).max);
                              }
                          }
                          /**
                           * @dev Returns the highest version that has been initialized. See {reinitializer}.
                           */
                          function _getInitializedVersion() internal view returns (uint8) {
                              return _initialized;
                          }
                          /**
                           * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                           */
                          function _isInitializing() internal view returns (bool) {
                              return _initializing;
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev This is the interface that {BeaconProxy} expects of its beacon.
                       */
                      interface IBeaconUpgradeable {
                          /**
                           * @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.8.3) (interfaces/IERC1967.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
                       *
                       * _Available since v4.9._
                       */
                      interface IERC1967Upgradeable {
                          /**
                           * @dev Emitted when the implementation is upgraded.
                           */
                          event Upgraded(address indexed implementation);
                          /**
                           * @dev Emitted when the admin account has changed.
                           */
                          event AdminChanged(address previousAdmin, address newAdmin);
                          /**
                           * @dev Emitted when the beacon is changed.
                           */
                          event BeaconUpgraded(address indexed beacon);
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.8.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 functionCallWithValue(target, data, 0, "Address: low-level call failed");
                          }
                          /**
                           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                           * `errorMessage` as a fallback revert reason when `target` reverts.
                           *
                           * _Available since v3.1._
                           */
                          function functionCall(
                              address target,
                              bytes memory data,
                              string memory errorMessage
                          ) internal returns (bytes memory) {
                              return functionCallWithValue(target, data, 0, errorMessage);
                          }
                          /**
                           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                           * but also transferring `value` wei to `target`.
                           *
                           * Requirements:
                           *
                           * - the calling contract must have an ETH balance of at least `value`.
                           * - the called Solidity function must be `payable`.
                           *
                           * _Available since v3.1._
                           */
                          function functionCallWithValue(
                              address target,
                              bytes memory data,
                              uint256 value
                          ) internal returns (bytes memory) {
                              return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                          }
                          /**
                           * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                           * with `errorMessage` as a fallback revert reason when `target` reverts.
                           *
                           * _Available since v3.1._
                           */
                          function functionCallWithValue(
                              address target,
                              bytes memory data,
                              uint256 value,
                              string memory errorMessage
                          ) internal returns (bytes memory) {
                              require(address(this).balance >= value, "Address: insufficient balance for call");
                              (bool success, bytes memory returndata) = target.call{value: value}(data);
                              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                          }
                          /**
                           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                           * but performing a static call.
                           *
                           * _Available since v3.3._
                           */
                          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                              return functionStaticCall(target, data, "Address: low-level static call failed");
                          }
                          /**
                           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                           * but performing a static call.
                           *
                           * _Available since v3.3._
                           */
                          function functionStaticCall(
                              address target,
                              bytes memory data,
                              string memory errorMessage
                          ) internal view returns (bytes memory) {
                              (bool success, bytes memory returndata) = target.staticcall(data);
                              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                          }
                          /**
                           * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                           * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                           *
                           * _Available since v4.8._
                           */
                          function verifyCallResultFromTarget(
                              address target,
                              bool success,
                              bytes memory returndata,
                              string memory errorMessage
                          ) internal view returns (bytes memory) {
                              if (success) {
                                  if (returndata.length == 0) {
                                      // only check isContract if the call was successful and the return data is empty
                                      // otherwise we already know that it was a contract
                                      require(isContract(target), "Address: call to non-contract");
                                  }
                                  return returndata;
                              } else {
                                  _revert(returndata, errorMessage);
                              }
                          }
                          /**
                           * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                           * revert reason or using the provided one.
                           *
                           * _Available since v4.3._
                           */
                          function verifyCallResult(
                              bool success,
                              bytes memory returndata,
                              string memory errorMessage
                          ) internal pure returns (bytes memory) {
                              if (success) {
                                  return returndata;
                              } else {
                                  _revert(returndata, errorMessage);
                              }
                          }
                          function _revert(bytes memory returndata, string memory errorMessage) private pure {
                              // Look for revert reason and bubble it up if present
                              if (returndata.length > 0) {
                                  // The easiest way to bubble the revert reason is using memory via assembly
                                  /// @solidity memory-safe-assembly
                                  assembly {
                                      let returndata_size := mload(returndata)
                                      revert(add(32, returndata), returndata_size)
                                  }
                              } else {
                                  revert(errorMessage);
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.7.0) (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) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                           */
                          function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                           */
                          function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                           */
                          function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := slot
                              }
                          }
                      }
                      // 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;
                      }