ETH Price: $2,163.24 (+0.92%)

Transaction Decoder

Block:
18867813 at Dec-26-2023 05:34:23 AM +UTC
Transaction Fee:
0.003631315449113884 ETH $7.86
Gas Used:
223,843 Gas / 16.222599988 Gwei

Emitted Events:

264 TransparentUpgradeableProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000b7dacb5abccca5db27997506bcc270c68a0ca4e8, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x00000000000000000000000000000000000000000000000000eb9872a0533f6d )

Account State Difference:

  Address   Before After State Difference Code
0x8C3c0274...3667A9E8b
(beaverbuild)
12.084036893177223962 Eth12.084059277477223962 Eth0.0000223843
0xB7DacB5A...68A0ca4e8
0.017128234121540977 Eth
Nonce: 460
0.013496918672427093 Eth
Nonce: 461
0.003631315449113884
0xb8D6eB76...54412B2D2

Execution Trace

TransparentUpgradeableProxy.aad3ec96( )
  • VaultHandlerV8Upgradable.claim( _nftAddress=0x8C3c0274c33f263F0A55d129cFC8eaa3667A9E8b, tokenId=66314237610508141 )
    • TransparentUpgradeableProxy.01ffc9a7( )
    • TransparentUpgradeableProxy.01ffc9a7( )
    • TransparentUpgradeableProxy.17ef7c54( )
      • ClaimedUpgradable.isClaimed( ) => ( False )
        • TransparentUpgradeableProxy.6352211e( )
          • EmblemVault.ownerOf( _tokenId=66314237610508141 ) => ( _owner=0xB7DacB5ABccca5Db27997506Bcc270c68A0ca4e8 )
          • TransparentUpgradeableProxy.6352211e( )
            • EmblemVault.ownerOf( _tokenId=66314237610508141 ) => ( _owner=0xB7DacB5ABccca5Db27997506Bcc270c68A0ca4e8 )
            • TransparentUpgradeableProxy.42966c68( )
              • EmblemVault.burn( _tokenId=66314237610508141 )
                • TransparentUpgradeableProxy.b68c4379( )
                  • VaultHandlerV8Upgradable.executeCallbacks( _from=0x23859b51117dbFBcdEf5b757028B18d7759a4460, _to=0x0000000000000000000000000000000000000000, tokenId=66314237610508141, _type=3 )
                  • TransparentUpgradeableProxy.9e96a260( )
                    • ClaimedUpgradable.claim( nftAddress=0x8C3c0274c33f263F0A55d129cFC8eaa3667A9E8b, tokenId=66314237610508141, _claimedBy=0xB7DacB5ABccca5Db27997506Bcc270c68A0ca4e8 )
                      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: 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 3 of 6: VaultHandlerV8Upgradable
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.8.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.
                           *
                           * 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 Internal function that returns the initialized version. Returns `_initialized`
                           */
                          function _getInitializedVersion() internal view returns (uint8) {
                              return _initialized;
                          }
                          /**
                           * @dev Internal function that returns the initialized version. Returns `_initializing`
                           */
                          function _isInitializing() internal view returns (bool) {
                              return _initializing;
                          }
                      }
                      // 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 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
                      pragma solidity 0.8.13;
                      interface BasicERC20 {
                          function burn(uint256 value) external;
                          function mint(address account, uint256 amount) external;
                          function decimals() external view returns (uint8);
                          function transferFrom(address from, address to, uint256 value) external returns (bool);
                          function totalSupply() external view returns (uint256);
                          function balanceOf(address who) external view returns (uint256);
                          function allowance(address owner, address spender) external view returns (uint256);
                      }
                      interface IERC20Token {
                          function transfer(address to, uint256 value) external returns (bool);
                          function approve(address spender, uint256 value) external returns (bool);
                          function transferFrom(address from, address to, uint256 value) external returns (bool);
                          function totalSupply() external view returns (uint256);
                          function balanceOf(address who) external view returns (uint256);
                          function allowance(address owner, address spender) external view returns (uint256);
                          event Transfer(address indexed from, address indexed to, uint256 value);
                          event Approval(address indexed owner, address indexed spender, uint256 value);
                      }// 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: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      contract ERC165 {
                          mapping(bytes4 => bool) private supportedInterfaces;
                          function initializeERC165() internal {
                              require(supportedInterfaces[0x01ffc9a7] == false, "Already Registered");
                              _registerInterface(0x01ffc9a7);
                          }
                          
                          function supportsInterface(bytes4 interfaceId) public view returns (bool) {
                              return supportedInterfaces[interfaceId];
                          }
                          
                          function _registerInterface(bytes4 interfaceId) internal {
                              require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
                              supportedInterfaces[interfaceId] = true;
                          }
                      }
                      // interface IERC1155Receiver {
                      //     function onERC1155Received(address operator, address from, uint256 id, uint256 value, bytes calldata data) external returns(bytes4);
                      //     function onERC1155BatchReceived(address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data) external returns(bytes4);
                      // }
                      // interface IERC1155MetadataURI  {
                      //     function uri(uint256 id) external view returns (string memory);
                      // }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./HasRegistration.sol";
                      import "./IHandlerCallback.sol";
                      contract HasCallbacksUpgradable is HasRegistration {
                          bool allowCallbacks;
                          
                          event CallbackExecuted(address _from, address _to, address target, uint256 tokenId, bytes4 targetFunction, IHandlerCallback.CallbackType _type, bytes returnData);
                          event CallbackReverted(address _from, address _to, address target, uint256 tokenId, bytes4 targetFunction, IHandlerCallback.CallbackType _type);
                          event CallbackFailed(address _from, address _to, address target, uint256 tokenId, bytes4 targetFunction, IHandlerCallback.CallbackType _type);
                          
                          mapping(address => mapping(uint256 => mapping(IHandlerCallback.CallbackType => IHandlerCallback.Callback[]))) public registeredCallbacks;
                          mapping(address => mapping(IHandlerCallback.CallbackType => IHandlerCallback.Callback[])) public registeredWildcardCallbacks;    
                          modifier isOwnerOrCallbackRegistrant(address _contract, address target, uint256 tokenId, IHandlerCallback.CallbackType _type, uint256 index) {
                              bool registrant = false;
                              if (hasTokenIdCallback(_contract, target, tokenId, _type)) {
                                  registrant = registeredCallbacks[_contract][tokenId][_type][index].registrant == _msgSender();
                              } else if(hasWildcardCallback(_contract, target, _type)) {
                                 registrant = registeredWildcardCallbacks[_contract][_type][index].registrant == _msgSender();
                              }        
                              require(_msgSender() == owner() || registrant, "Not owner or Callback registrant");
                              _;
                          }
                          function executeCallbacks(address _from, address _to, uint256 tokenId, IHandlerCallback.CallbackType _type) public isRegisteredContract(_msgSender()) {
                              if (allowCallbacks) {
                                  IHandlerCallback.Callback[] memory callbacks = registeredCallbacks[_msgSender()][tokenId][_type];
                                  if (callbacks.length > 0) executeCallbackLoop(callbacks, _from, _to, tokenId, _type);
                                  IHandlerCallback.Callback[] memory wildCardCallbacks = registeredWildcardCallbacks[_msgSender()][_type];
                                  if (wildCardCallbacks.length > 0) executeCallbackLoop(wildCardCallbacks, _from, _to, tokenId, _type);
                              }
                          }
                          function executeCallbacksInternal(address _nftAddress, address _from, address _to, uint256 tokenId, IHandlerCallback.CallbackType _type) internal isRegisteredContract(_nftAddress) {
                               if (allowCallbacks) {
                                  IHandlerCallback.Callback[] memory callbacks = registeredCallbacks[_nftAddress][tokenId][_type];
                                  if (callbacks.length > 0) executeCallbackLoop(callbacks, _from, _to, tokenId, _type);
                                  IHandlerCallback.Callback[] memory wildCardCallbacks = registeredWildcardCallbacks[_nftAddress][_type];
                                  if (wildCardCallbacks.length > 0) executeCallbackLoop(wildCardCallbacks, _from, _to, tokenId, _type);
                               }
                          }
                          function executeCallbackLoop(IHandlerCallback.Callback[] memory callbacks, address _from, address _to, uint256 tokenId, IHandlerCallback.CallbackType _type) internal {
                              bool canRevert = false;  
                              for (uint256 i = 0; i < callbacks.length; ++i) {            
                                  IHandlerCallback.Callback memory cb = callbacks[i];    
                                  canRevert = cb.canRevert;
                                  if (cb.target != address(0)){
                                      (bool success, bytes memory returnData) =
                                          address(cb.target).call(
                                              abi.encodePacked(
                                                  cb.targetFunction,
                                                  abi.encode(_from),
                                                  abi.encode(_to),
                                                  abi.encode(tokenId)
                                              )
                                          );
                                      if (success) {
                                          emit CallbackExecuted(_from, _to, cb.target, tokenId, cb.targetFunction, _type, returnData);
                                      } else if (canRevert) {
                                          emit CallbackReverted(_from, _to, cb.target, tokenId, cb.targetFunction, _type);
                                          revert("Callback Reverted");
                                      } else {
                                          emit CallbackFailed(_from, _to, cb.target, tokenId, cb.targetFunction, _type);
                                      }
                                  }
                              }
                          }
                          function toggleAllowCallbacks() public onlyOwner {
                              allowCallbacks = !allowCallbacks;
                          }
                          function registerCallback(address _contract, address target, uint256 tokenId, IHandlerCallback.CallbackType _type, bytes4 _function, bool allowRevert) isRegisteredContract(_contract) onlyOwner public {
                              registeredCallbacks[_contract][tokenId][_type].push(IHandlerCallback.Callback(_contract, _msgSender(), target, _function, allowRevert ));
                          }
                          function registerWildcardCallback(address _contract, address target, IHandlerCallback.CallbackType _type, bytes4 _function, bool allowRevert) isRegisteredContract(_contract) onlyOwner public {
                              registeredWildcardCallbacks[_contract][_type].push(IHandlerCallback.Callback(_contract, _msgSender(), target, _function, allowRevert ));
                          }
                          function hasCallback(address _contract, address target, uint256 tokenId, IHandlerCallback.CallbackType _type) public view returns (bool ) {
                              bool found = hasTokenIdCallback(_contract, target, tokenId, _type);
                              if (found) return true;
                              return hasWildcardCallback(_contract, target, _type);
                          }
                          function hasTokenIdCallback(address _contract, address target, uint256 tokenId, IHandlerCallback.CallbackType _type) internal view returns(bool) {
                              bool found = false;
                              IHandlerCallback.Callback[] memory callbacks = registeredCallbacks[_contract][tokenId][_type];
                              for (uint256 i = 0; i < callbacks.length; ++i) {
                                  if (callbacks[i].target == target) {
                                      found = true;
                                  }
                              }
                              return found;
                          }
                          function hasWildcardCallback(address _contract, address target, IHandlerCallback.CallbackType _type) internal view returns(bool) {
                              bool found = false;
                              IHandlerCallback.Callback[] memory callbacks = registeredWildcardCallbacks[_contract][_type];
                              for (uint256 i = 0; i < callbacks.length; ++i) {
                                  if (callbacks[i].target == target) {
                                      found = true;
                                  }
                              }
                              return found;
                          }
                          function unregisterCallback(address _contract, address target, uint256 tokenId, IHandlerCallback.CallbackType _type, uint256 index) public isOwnerOrCallbackRegistrant(_contract, target, tokenId, _type, index){
                              if (hasTokenIdCallback(_contract, target, tokenId, _type)) {
                                  IHandlerCallback.Callback[] storage arr = registeredCallbacks[_contract][tokenId][_type];
                                  arr[index] = arr[arr.length - 1];
                                  arr.pop();
                                  // delete registeredCallbacks[_contract][tokenId][_type][index];
                              }
                              else if(hasWildcardCallback(_contract, target, _type)) {
                                  IHandlerCallback.Callback[] storage arr = registeredWildcardCallbacks[_contract][_type];
                                  arr[index] = arr[arr.length - 1];
                                  arr.pop();
                                  // delete registeredWildcardCallbacks[_contract][_type][index];
                              }
                          }
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./IsBypassable.sol";
                      contract HasRegistration is IsBypassable {
                          mapping(address => uint256) public registeredContracts; // 0 EMPTY, 1 ERC1155, 2 ERC721, 3 HANDLER, 4 ERC20, 5 BALANCE, 6 CLAIM, 7 UNKNOWN, 8 FACTORY, 9 STAKING, 10 BYPASS
                          mapping(uint256 => address[]) internal registeredOfType;
                          modifier isRegisteredContract(address _contract) {
                              require(registeredContracts[_contract] > 0, "Contract is not registered");
                              _;
                          }
                          modifier isRegisteredContractOrOwner(address _contract) {
                              require(registeredContracts[_contract] > 0 || owner() == _msgSender(), "Contract is not registered nor Owner");
                              _;
                          }
                          function registerContract(address _contract, uint _type) public isRegisteredContractOrOwner(_msgSender()) {
                              registeredContracts[_contract] = _type;
                              registeredOfType[_type].push(_contract);
                          }
                          function unregisterContract(address _contract, uint256 index) public onlyOwner isRegisteredContract(_contract) {
                              address[] storage arr = registeredOfType[registeredContracts[_contract]];
                              arr[index] = arr[arr.length - 1];
                              arr.pop();
                              delete registeredContracts[_contract];
                          }
                          function isRegistered(address _contract, uint256 _type) public view returns (bool) {
                              return registeredContracts[_contract] == _type;
                          }
                          function getAllRegisteredContractsOfType(uint256 _type) public view returns (address[] memory) {
                              return registeredOfType[_type];
                          }
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      interface IClaimed {
                          function isClaimed(address nftAddress, uint tokenId, bytes32[] calldata proof) external returns(bool);
                          function claim(address nftAddress, uint tokenId, address _claimedBy) external;
                      }// SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.4;
                      interface IERC1155 {
                          event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
                          event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);
                          event ApprovalForAll(address indexed account, address indexed operator, bool approved);
                          event URI(string value, uint256 indexed id);
                          function balanceOf(address account, uint256 id) external view returns (uint256);
                          function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);
                          function setApprovalForAll(address operator, bool approved) external;
                          function isApprovedForAll(address account, address operator) external view returns (bool);
                          function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
                          function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
                          function mint(address _to, uint256 _tokenId, uint256 _amount) external;
                          function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes[] memory serialNumbers) external;
                          function burn(address _from, uint256 _tokenId, uint256 _amount) external;
                          function mintWithSerial(address _to, uint256 _tokenId, uint256 _amount, bytes memory serialNumber) external;
                      }
                      interface IERC1155Receiver {
                          function onERC1155Received(address operator, address from, uint256 id, uint256 value, bytes calldata data) external returns(bytes4);
                          function onERC1155BatchReceived(address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data) external returns(bytes4);
                      }
                      interface IERC1155MetadataURI  {
                          function uri(uint256 id) external view returns (string memory);
                      }// SPDX-License-Identifier: MIT
                      pragma solidity 0.8.13;
                      interface IERC165 {
                          function supportsInterface(bytes4 interfaceId) external view returns (bool);
                      }// SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.4;
                      interface IERC721 {
                          function burn(uint256 tokenId) external;
                          function transferFrom(address from, address to, uint256 tokenId) external;
                          function mint( address _to, uint256 _tokenId, string calldata _uri, string calldata _payload) external;
                          function changeName(string calldata name, string calldata symbol) external;
                          function updateTokenUri(uint256 _tokenId,string memory _uri) external;
                          function tokenPayload(uint256 _tokenId) external view returns (string memory);
                          function ownerOf(uint256 _tokenId) external view returns (address _owner);
                          function getApproved(uint256 _tokenId) external returns (address);
                          function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
                          function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external;
                          function totalSupply() external view returns (uint256);
                          function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
                          function tokenByIndex(uint256 _index) external view returns (uint256);
                          function balanceOf(address account, uint256 id) external view returns (uint256);
                          function isApprovedForAll(address _owner, address _operator) external view returns (bool);
                          function setApprovalForAll( address _operator, bool _approved) external;
                      }
                      /**
                       * @title ERC721 token receiver interface
                       * @dev Interface for any contract that wants to support safeTransfers
                       * from ERC721 asset contracts.
                       */
                      interface IERC721Receiver {
                          /**
                           * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
                           * by `operator` from `from`, this function is called.
                           *
                           * It must return its Solidity selector to confirm the token transfer.
                           * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
                           *
                           * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
                           */
                          function onERC721Received(
                              address operator,
                              address from,
                              uint256 tokenId,
                              bytes calldata data
                          ) external returns (bytes4);
                      }// 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: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      interface IHandlerCallback {
                          enum CallbackType {
                              MINT, TRANSFER, CLAIM, BURN, FALLBACK
                          }
                          struct Callback {
                              address vault;
                              address registrant;
                              address target;
                              bytes4 targetFunction;
                              bool canRevert;
                          }
                          function executeCallbacksInternal(address _from, address _to, uint256 tokenId, CallbackType _type) external;
                          function executeCallbacks(address _from, address _to, uint256 tokenId, CallbackType _type) external;
                          function executeStoredCallbacksInternal(address _nftAddress, address _from, address _to, uint256 tokenId, IHandlerCallback.CallbackType _type) external;
                          
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      interface IIsSerialized {
                          function isSerialized() external view returns (bool);
                          function getSerial(uint256 tokenId, uint256 index) external view returns (uint256);
                          function getFirstSerialByOwner(address owner, uint256 tokenId) external view returns (uint256);
                          function getOwnerOfSerial(uint256 serialNumber) external view returns (address);
                          function getSerialByOwnerAtIndex(address _owner, uint256 tokenId, uint256 index) external view returns (uint256);
                          function getTokenIdForSerialNumber(uint256 serialNumber) external view returns (uint256);
                          function isOverloadSerial() external view returns (bool);
                      }// SPDX-License-Identifier: MIT
                      pragma solidity 0.8.13;
                      interface IMintVaultQuote {
                          function initialize() external;
                          function setPair(address _pair) external;
                          function setUsdPrice(uint256 _usdPrice) external;
                          function addDiscountToken(address _discountToken, uint256 amount, uint256 discount) external;
                          function updateDiscountToken(uint256 index, address _discountToken, uint256 amount, uint256 discount) external;
                          function removeDiscountToken(uint256 index) external;
                          function addMintPass(address _mintPass, uint256 tokenId, uint256 price) external;
                          function updateMintPass(uint256 index, address _mintPass, uint256 tokenId, uint256 price) external;
                          function removeMintPass(uint256 index) external;
                          function getUsdPriceInEth(uint256 _usdPrice) external view returns (uint256);
                          function getReserves() external view returns (uint112 reserve0, uint112 reserve1);
                          function quoteExternalPrice(address buyer, uint256 _usdPrice) external view returns (uint256);
                          function quoteStoredPrice(address buyer) external view returns (uint256);
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./IsClaimable.sol";
                      // import "operator-filter-registry/src/upgradeable/OperatorFiltererUpgradeable.sol";
                      abstract contract IsBypassable is IsClaimable {
                          bool public byPassable;
                          mapping(address => mapping(bytes4 => bool)) public byPassableFunction;
                          mapping(address => mapping(uint256 => bool)) byPassableIds;
                          modifier onlyOwner virtual override {
                              bool _canBypass = byPassable && byPassableFunction[_msgSender()][msg.sig];
                              require(owner() == _msgSender() || _canBypass, "Not owner or able to bypass");        
                                  _;
                          }
                          modifier onlyOwnerOrBypassWithId(uint256 id) {
                              require (owner() == _msgSender() || (id != 0 && byPassableIds[_msgSender()][id] ), "Invalid id");
                                  _;
                          }
                          function canBypass() internal view returns(bool) {
                              return (byPassable && byPassableFunction[_msgSender()][msg.sig]);
                          }
                          function canBypassForTokenId(uint256 id) internal view returns(bool) {
                              return (byPassable && canBypass() && byPassableIds[_msgSender()][id]);
                          }
                          function toggleBypassability() public onlyOwner {
                            byPassable = !byPassable;
                          }
                          function addBypassRule(address who, bytes4 functionSig, uint256 id) public onlyOwner {
                              byPassableFunction[who][functionSig] = true;
                              if (id != 0) {
                                  byPassableIds[who][id] = true;
                              }        
                          }
                          function removeBypassRule(address who, bytes4 functionSig, uint256 id) public onlyOwner {
                              byPassableFunction[who][functionSig] = false;
                              if (id !=0) {
                                  byPassableIds[who][id] = true;
                              }
                          }
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./OwnableUpgradeable.sol";
                      abstract contract IsClaimable is OwnableUpgradeable {
                          bool public isClaimable;
                          function toggleClaimable() public onlyOwner {
                              isClaimable = !isClaimable;
                          }
                         
                      }// SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
                      import "@openzeppelin/contracts-upgradeable/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 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() 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: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      /**
                       * @dev Contract module that helps prevent reentrant calls to a function.
                       *
                       * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
                       * available, which can be applied to functions to make sure there are no nested
                       * (reentrant) calls to them.
                       *
                       * Note that because there is a single `nonReentrant` guard, functions marked as
                       * `nonReentrant` may not call one another. This can be worked around by making
                       * those functions `private`, and then adding `external` `nonReentrant` entry
                       * points to them.
                       *
                       * TIP: If you would like to learn more about reentrancy and alternative ways
                       * to protect against it, check out our blog post
                       * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
                       */
                      contract ReentrancyGuardUpgradable {
                          // Booleans are more expensive than uint256 or any type that takes up a full
                          // word because each write operation emits an extra SLOAD to first read the
                          // slot's contents, replace the bits taken up by the boolean, and then write
                          // back. This is the compiler's defense against contract upgrades and
                          // pointer aliasing, and it cannot be disabled.
                          // The values being non-zero value makes deployment a bit more expensive,
                          // but in exchange the refund on every call to nonReentrant will be lower in
                          // amount. Since refunds are capped to a percentage of the total
                          // transaction's gas, it is best to keep them low in cases like this one, to
                          // increase the likelihood of the full refund coming into effect.
                          uint256 private _NOT_ENTERED;
                          uint256 private _ENTERED;
                          uint256 private _status;
                          function init() internal {
                               _NOT_ENTERED = 1;
                               _ENTERED = 2;
                              _status = _NOT_ENTERED;
                          }
                          /**
                           * @dev Prevents a contract from calling itself, directly or indirectly.
                           * Calling a `nonReentrant` function from another `nonReentrant`
                           * function is not supported. It is possible to prevent this from happening
                           * by making the `nonReentrant` function external, and make it call a
                           * `private` function that does the actual work.
                           */
                          modifier nonReentrant() {
                              // On the first call to nonReentrant, _notEntered will be true
                              require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                              // Any calls to nonReentrant after this point will fail
                              _status = _ENTERED;
                              _;
                              // By storing the original value once again, a refund is triggered (see
                              // https://eips.ethereum.org/EIPS/eip-2200)
                              _status = _NOT_ENTERED;
                          }
                      }// SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.4;
                      library SafeMath {
                          function add(uint256 a, uint256 b) internal pure returns (uint256) {
                              uint256 c = a + b;
                              require(c >= a, "SafeMath: addition overflow");
                              return c;
                          }
                          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                              return sub(a, b, "SafeMath: subtraction overflow");
                          }
                          function sub(
                              uint256 a,
                              uint256 b,
                              string memory errorMessage
                          ) internal pure returns (uint256) {
                              require(b <= a, errorMessage);
                              uint256 c = a - b;
                              return c;
                          }
                          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                              if (a == 0) {
                                  return 0;
                              }
                              uint256 c = a * b;
                              require(c / a == b, "SafeMath: multiplication overflow");
                              return c;
                          }
                          function div(uint256 a, uint256 b) internal pure returns (uint256) {
                              return div(a, b, "SafeMath: division by zero");
                          }
                          function div(
                              uint256 a,
                              uint256 b,
                              string memory errorMessage
                          ) internal pure returns (uint256) {
                              // Solidity only automatically asserts when dividing by 0
                              require(b > 0, errorMessage);
                              uint256 c = a / b;
                              return c;
                          }
                      }//     ______          __    __                          
                      //    / ____/___ ___  / /_  / /__  ____ ___              
                      //   / __/ / __ `__ \\/ __ \\/ / _ \\/ __ `__ \\             
                      //  / /___/ / / / / / /_/ / /  __/ / / / / /             
                      // /_____/_/ /_/ /_/_.___/_/\\___/_/ /_/ /_/              
                      // | |  / /___ ___  __/ / /_                             
                      // | | / / __ `/ / / / / __/                             
                      // | |/ / /_/ / /_/ / / /_                               
                      // |___/\\__,_/\\__,_/_/\\__/                               
                      //     __  __                ____                   ____ 
                      //    / / / /___ _____  ____/ / /__  _____   _   __( __ ) (upgradable)
                      //   / /_/ / __ `/ __ \\/ __  / / _ \\/ ___/  | | / / __  |
                      //  / __  / /_/ / / / / /_/ / /  __/ /      | |/ / /_/ / 
                      // /_/ /_/\\__,_/_/ /_/\\__,_/_/\\___/_/       |___/\\____/  
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.13;
                      import "./BasicERC20.sol";
                      import "./IIsSerialized.sol";
                      import "./SafeMath.sol";
                      import "./IERC721.sol";
                      import "./IERC165.sol";
                      import "./IERC1155.sol";
                      import "./IClaimed.sol";
                      import "./ERC165.sol";
                      import "./IMintVaultQuote.sol";
                      import "./ReentrancyGuardUpgradable.sol";
                      import "./HasCallbacksUpgradable.sol";
                      import "./BytesLib.sol";
                      import "./IERC721AUpgradeable.sol";
                      interface IERC721A {
                          function mint(address _to, uint256 _tokenId) external;
                          function getInternalTokenId(uint256 tokenId) external view returns (uint256);
                          function ownerOf(uint256 tokenId) external view returns (address owner);
                          function burn(uint256 tokenId) external;
                      }
                      contract VaultHandlerV8Upgradable is ReentrancyGuardUpgradable, HasCallbacksUpgradable, ERC165 {
                          
                          using SafeMath for uint256;
                          string public metadataBaseUri;
                          bool public initialized;
                          address public recipientAddress;
                          bytes4 private _INTERFACE_ID_ERC1155;
                          bytes4 private _INTERFACE_ID_ERC20;
                          bytes4 private _INTERFACE_ID_ERC721;
                          bool public shouldBurn;
                          
                          mapping(address => bool) public witnesses;
                          mapping(uint256 => bool) usedNonces;
                          
                          address private quoteContract;
                          bytes4 private _INTERFACE_ID_ERC721A;
                          
                          function initialize() public initializer {
                              __Ownable_init();
                              addWitness(owner());
                              ReentrancyGuardUpgradable.init();
                              metadataBaseUri = "https://v2.emblemvault.io/meta/";
                              _INTERFACE_ID_ERC1155 = 0xd9b67a26;
                              _INTERFACE_ID_ERC20 = 0x74a1476f;
                              _INTERFACE_ID_ERC721 = 0x80ac58cd;
                              _INTERFACE_ID_ERC721A = 0xf4a95f26;
                              recipientAddress = _msgSender();
                              HasCallbacksUpgradable.allowCallbacks = true;        
                              initializeERC165();
                              initialized = true;
                          }
                          function upgradeInit() public onlyOwner {
                              _INTERFACE_ID_ERC721A = 0xf4a95f26;
                          }
                          function updateQuoteContract(address _address) public onlyOwner() {
                              quoteContract = _address;
                          }
                          function claim(address _nftAddress, uint256 tokenId) public nonReentrant isRegisteredContract(_nftAddress) {
                              IClaimed claimer = IClaimed(registeredOfType[6][0]);
                              bytes32[] memory proof;
                              
                              if (IERC165(_nftAddress).supportsInterface(_INTERFACE_ID_ERC1155)) {
                                  IIsSerialized serialized = IIsSerialized(_nftAddress);
                                  uint256 serialNumber = serialized.getFirstSerialByOwner(_msgSender(), tokenId);
                                  require(serialized.getTokenIdForSerialNumber(serialNumber) == tokenId, "Invalid tokenId serialnumber combination");
                                  require(serialized.getOwnerOfSerial(serialNumber) == _msgSender(), "Not owner of serial number");
                                  require(!claimer.isClaimed(_nftAddress, serialNumber, proof), "Already Claimed");
                                  IERC1155(_nftAddress).burn(_msgSender(), tokenId, 1);
                                  claimer.claim(_nftAddress, serialNumber, _msgSender());
                              } else {            
                                  if (IERC165(_nftAddress).supportsInterface(_INTERFACE_ID_ERC721A)){
                                      IERC721A token = IERC721A(_nftAddress);
                                      uint256 internalTokenId = token.getInternalTokenId(tokenId);
                                      require(!claimer.isClaimed(_nftAddress, internalTokenId, proof), "Already Claimed");
                                      require(token.ownerOf(internalTokenId) == _msgSender(), "Not Token Owner");
                                      token.burn(internalTokenId);
                                  } else {
                                      require(!claimer.isClaimed(_nftAddress, tokenId, proof), "Already Claimed");
                                      IERC721 token = IERC721(_nftAddress);
                                      require(token.ownerOf(tokenId) == _msgSender(), "Not Token Owner");
                                      token.burn(tokenId);                
                                  }
                                  claimer.claim(_nftAddress, tokenId, _msgSender());
                              }
                              executeCallbacksInternal(_nftAddress, _msgSender(), address(0), tokenId, IHandlerCallback.CallbackType.CLAIM);
                          }
                          function buyWithSignedPrice(address _nftAddress, address _payment, uint _price, address _to, uint256 _tokenId, uint256 _nonce, bytes calldata _signature, bytes calldata serialNumber, uint256 _amount) public nonReentrant {
                              IERC20Token paymentToken = IERC20Token(_payment);
                              if (shouldBurn) {
                                  require(paymentToken.transferFrom(msg.sender, address(this), _price), 'Transfer ERROR'); // Payment sent to recipient
                                  BasicERC20(_payment).burn(_price);
                              } else {
                                  require(paymentToken.transferFrom(msg.sender, address(recipientAddress), _price), 'Transfer ERROR'); // Payment sent to recipient
                              }
                              address signer = getAddressFromSignature(_nftAddress, _payment, _price, _to, _tokenId, _nonce, _amount, _signature);
                              handleMint(_nftAddress, _to, _tokenId, _nonce, _amount, signer, serialNumber);
                          }
                          function buyWithQuote(address _nftAddress, uint _price, address _to, uint256 _tokenId, uint256 _nonce, bytes calldata _signature, bytes calldata serialNumber, uint256 _amount) public payable nonReentrant {
                              uint256 quote = IMintVaultQuote(quoteContract).quoteExternalPrice(_msgSender(), _price);
                              uint256 totalPrice = quote * _amount;
                              // Calculate the acceptable range for the msg.value
                              uint256 acceptableRange = totalPrice.mul(2).div(100); // 2% of totalPrice
                              require(
                                  msg.value >= totalPrice.sub(acceptableRange) && msg.value <= totalPrice.add(acceptableRange),
                                  "The sent amount is outside the acceptable range"
                              );
                              payable(recipientAddress).transfer(msg.value);
                              address signer = getAddressFromSignatureQuote(_nftAddress, _price, _to, _tokenId, _nonce, _amount, _signature);
                              handleMint(_nftAddress, _to, _tokenId, _nonce, _amount, signer, serialNumber);        
                          }
                          function handleMint(address _nftAddress, address _to, uint256 _tokenId, uint256 _nonce, uint256 _amount, address signer, bytes calldata serialNumber) internal {
                              require(witnesses[signer], 'Not Witnessed');
                              usedNonces[_nonce] = true;        
                              if (IERC165(_nftAddress).supportsInterface(_INTERFACE_ID_ERC1155)) {
                                  if (IIsSerialized(_nftAddress).isOverloadSerial()) {
                                      IERC1155(_nftAddress).mintWithSerial(_to, _tokenId, _amount, serialNumber);
                                  } else {
                                      IERC1155(_nftAddress).mint(_to, _tokenId, _amount);
                                  }
                              } else {
                                  if (IERC165(_nftAddress).supportsInterface(_INTERFACE_ID_ERC721A)) {
                                      IERC721A(_nftAddress).mint(_to, _tokenId);
                                  } else {
                                      string memory _uri = concat(metadataBaseUri, uintToStr(_tokenId));
                                      IERC721(_nftAddress).mint(_to, _tokenId, _uri, '');
                                  }
                              }
                          }
                          function mint(address _nftAddress, address _to, uint256 _tokenId, string calldata _uri, string calldata _payload, uint256 amount) external onlyOwner {
                              if (IERC165(_nftAddress).supportsInterface(_INTERFACE_ID_ERC1155)) {
                                  IERC1155(_nftAddress).mint(_to, _tokenId, amount);
                              } else {
                                  if (IERC165(_nftAddress).supportsInterface(_INTERFACE_ID_ERC721A)) {
                                      IERC721A(_nftAddress).mint(_to, _tokenId);
                                  } else {
                                      IERC721(_nftAddress).mint(_to, _tokenId, _uri, _payload);
                                  }
                              }        
                          }
                          function moveVault(address _from, address _to, uint256 tokenId, uint256 newTokenId, uint256 nonce, bytes calldata signature, bytes memory serialNumber) external nonReentrant isRegisteredContract(_from) isRegisteredContract(_to)  {
                              require(_from != _to, 'Cannot move vault to same address');
                              require(witnesses[getAddressFromSignatureHash(keccak256(abi.encodePacked(_from, _to, tokenId, newTokenId, serialNumber, nonce)), signature)], 'Not Witnessed');
                              usedNonces[nonce] = true;
                              if (IERC165(_from).supportsInterface(_INTERFACE_ID_ERC1155)) {
                                  require(tokenId != newTokenId, 'from: TokenIds must be different for ERC1155');
                                  require(IERC1155(_from).balanceOf(_msgSender(), tokenId) > 0, 'from: Not owner of vault');
                                  IERC1155(_from).burn(_msgSender(), tokenId, 1);
                              } else {
                                  require(IERC721(_from).ownerOf(tokenId) == _msgSender(), 'from: Not owner of vault');
                                  IERC721(_from).burn(tokenId);
                              }
                              if (IERC165(_to).supportsInterface(_INTERFACE_ID_ERC1155)) {
                                  require(tokenId != newTokenId, 'to: TokenIds must be different for ERC1155');
                                  if (IIsSerialized(_to).isOverloadSerial()) {
                                      require(BytesLib.toUint256(serialNumber, 0) != 0, "Handler: must provide serial number");
                                      IERC1155(_to).mintWithSerial(_msgSender(), newTokenId, 1, serialNumber);
                                  } else {
                                      IERC1155(_to).mint(_msgSender(), newTokenId, 1);
                                  }
                              } else {
                                  if (supportsInterface(_INTERFACE_ID_ERC721A)) {
                                      IERC721A(_to).mint(_msgSender(), newTokenId);
                                  } else {
                                      IERC721(_to).mint(_msgSender(), newTokenId, concat(metadataBaseUri, uintToStr(newTokenId)), "");
                                  }
                              }
                          }  
                          
                          function toggleShouldBurn() public onlyOwner {
                              shouldBurn = !shouldBurn;
                          }
                          
                          function addWitness(address _witness) public onlyOwner {
                              witnesses[_witness] = true;
                          }
                          function removeWitness(address _witness) public onlyOwner {
                              witnesses[_witness] = false;
                          }
                          function getAddressFromSignatureHash(bytes32 _hash, bytes calldata signature) internal pure returns (address) {
                              address addressFromSig = recoverSigner(_hash, signature);
                              return addressFromSig;
                          }
                          function getAddressFromSignature(address _nftAddress, address _payment, uint _price, address _to, uint256 _tokenId, uint256 _nonce, uint256 _amount, bytes calldata signature) internal view returns (address) {
                              require(!usedNonces[_nonce], 'Nonce already used');
                              return getAddressFromSignatureHash(keccak256(abi.encodePacked(_nftAddress, _payment, _price, _to, _tokenId, _nonce, _amount)), signature);
                          }
                          function getAddressFromSignatureQuote(address _nftAddress, uint _price, address _to, uint256 _tokenId, uint256 _nonce, uint256 _amount, bytes calldata signature) internal view returns (address) {
                              require(!usedNonces[_nonce], 'Nonce already used');
                              return getAddressFromSignatureHash(keccak256(abi.encodePacked(_nftAddress, _price, _to, _tokenId, _nonce, _amount)), signature);
                          }
                          function getAddressFromSignatureMint(address _nftAddress, address _to, uint256 _tokenId, uint256 _nonce, string calldata payload, bytes calldata signature) internal view returns (address) {
                              require(!usedNonces[_nonce]);
                              return getAddressFromSignatureHash(keccak256(abi.encodePacked(_nftAddress, _to, _tokenId, _nonce, payload)), signature);
                          }
                          function getAddressFromSignatureMove(address _from, address _to, uint256 tokenId, uint256 newTokenId, uint256 _nonce, bytes memory serialNumber, bytes calldata signature) internal view returns (address) {
                              require(!usedNonces[_nonce]);
                              return getAddressFromSignatureHash(keccak256(abi.encodePacked(_from, _to, tokenId, newTokenId, serialNumber, _nonce)), signature);
                          }
                          
                          function changeMetadataBaseUri(string calldata _uri) public onlyOwner {
                              metadataBaseUri = _uri;
                          }
                          
                          function transferNftOwnership(address _nftAddress, address newOwner) external onlyOwner {
                              OwnableUpgradeable(_nftAddress).transferOwnership(newOwner);
                          }
                          function changeRecipient(address _recipient) public onlyOwner {
                             recipientAddress = _recipient;
                          }
                          function concat(string memory a, string memory b) internal pure returns (string memory) {
                              return string(abi.encodePacked(a, b));
                          }
                          function recoverSigner(bytes32 hash, bytes memory sig) internal pure returns (address) {
                              require(sig.length == 65, "Require correct length");
                              bytes32 r;
                              bytes32 s;
                              uint8 v;
                              // Divide the signature in r, s and v variables
                              assembly {
                                  r := mload(add(sig, 32))
                                  s := mload(add(sig, 64))
                                  v := byte(0, mload(add(sig, 96)))
                              }
                              // Version of signature should be 27 or 28, but 0 and 1 are also possible versions
                              if (v < 27) {
                                  v += 27;
                              }
                              require(v == 27 || v == 28, "Signature version not match");
                              return recoverSigner2(hash, v, r, s);
                          }
                          function recoverSigner2(bytes32 h, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
                              bytes memory prefix = "\\x19Ethereum Signed Message:\
                      32";
                              bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, h));
                              address addr = ecrecover(prefixedHash, v, r, s);
                              return addr;
                          }
                          
                          function uintToStr(uint _i) internal pure returns (string memory _uintAsString) {
                              if (_i == 0) {
                                  return "0";
                              }
                              uint j = _i;
                              uint len;
                              while (j != 0) {
                                  len++;
                                  j /= 10;
                              }
                              bytes memory bstr = new bytes(len);
                              uint k = len;
                              while (_i != 0) {
                                  k = k-1;
                                  uint8 temp = (48 + uint8(_i - _i / 10 * 10));
                                  bytes1 b1 = bytes1(temp);
                                  bstr[k] = b1;
                                  _i /= 10;
                              }
                              return string(bstr);
                          }
                          function version() public pure returns (string memory) {
                              return "2.0.10";
                          }
                      }

                      File 4 of 6: EmblemVault
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.8.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.
                           *
                           * 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 Internal function that returns the initialized version. Returns `_initialized`
                           */
                          function _getInitializedVersion() internal view returns (uint8) {
                              return _initialized;
                          }
                          /**
                           * @dev Internal function that returns the initialized version. Returns `_initializing`
                           */
                          function _isInitializing() internal view returns (bool) {
                              return _initializing;
                          }
                      }
                      // 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 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: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      interface IClonable {
                          function initialize() external;
                          function version() external returns(uint256);  
                      }
                      abstract contract Clonable {
                          function initialize() public virtual;
                          function version() public pure virtual returns (uint256) {
                              return 1;
                          }
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.13;
                      pragma experimental ABIEncoderV2;
                      import "./SafeMath.sol";
                      import "./ERC165.sol";
                      import "./HasRegistration.sol";
                      import "./IHandlerCallback.sol";
                      import "./IsBypassable.sol";
                      import "./Clonable.sol";
                      import "./Stream.sol";
                      import "./ERC2981Royalties.sol";
                      import "./EventableERC721.sol";
                      import "operator-filter-registry/src/upgradeable/OperatorFiltererUpgradeable.sol";
                      library AddressUtils {
                        
                        function isContract(
                          address _addr
                        )
                          internal
                          view
                          returns (bool addressCheck)
                        {
                          
                          bytes32 codehash;
                          bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                          assembly { codehash := extcodehash(_addr) } // solhint-disable-line
                          addressCheck = (codehash != 0x0 && codehash != accountHash);
                        }
                      }
                      contract NFToken is ERC165, HasRegistration, EventableERC721, OperatorFiltererUpgradeable {
                        using SafeMath for uint256;
                        using AddressUtils for address;
                        /**
                         * List of revert message codes. Implementing dApp should handle showing the correct message.
                         * Based on 0xcert framework error codes.
                         */
                        string constant ZERO_ADDRESS = "003001";
                        string constant NOT_VALID_NFT = "003002";
                        string constant NOT_OWNER_OR_OPERATOR = "003003";
                        string constant NOT_OWNER_APPROVED_OR_OPERATOR = "003004";
                        string constant NOT_ABLE_TO_RECEIVE_NFT = "003005";
                        string constant NFT_ALREADY_EXISTS = "003006";
                        string constant NOT_OWNER = "003007";
                        string constant IS_OWNER = "003008";
                        /**
                         * @dev Magic value of a smart contract that can recieve NFT.
                         * Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")).
                         */
                        bytes4 internal constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02;
                        /**
                         * @dev A mapping from NFT ID to the address that owns it.
                         */
                        mapping (uint256 => address) internal idToOwner;
                        /**
                         * @dev Mapping from NFT ID to approved address.
                         */
                        mapping (uint256 => address) internal idToApproval;
                         /**
                         * @dev Mapping from owner address to count of his tokens.
                         */
                        mapping (address => uint256) private ownerToNFTokenCount;
                        /**
                         * @dev Mapping from owner address to mapping of operator addresses.
                         */
                        mapping (address => mapping (address => bool)) internal ownerToOperators;
                        /**
                         * @dev Guarantees that the msg.sender is an owner or operator of the given NFT.
                         * @param _tokenId ID of the NFT to validate.
                         */
                        modifier canOperate(
                          uint256 _tokenId
                        )
                        {
                          address tokenOwner = idToOwner[_tokenId];
                          require(tokenOwner == _msgSender() || ownerToOperators[tokenOwner][_msgSender()], NOT_OWNER_OR_OPERATOR);
                          _;
                        }
                        /**
                         * @dev Guarantees that the msg.sender is allowed to transfer NFT.
                         * @param _tokenId ID of the NFT to transfer.
                         */
                        modifier canTransfer(uint256 _tokenId) {
                          bool _canBypass = canBypass();
                          bool hasOldBalance;
                          
                          address tokenOwner = idToOwner[_tokenId];
                          require(
                            tokenOwner == _msgSender()
                            || idToApproval[_tokenId] == _msgSender()
                            || ownerToOperators[tokenOwner][_msgSender()]
                            || _canBypass,
                            NOT_OWNER_APPROVED_OR_OPERATOR
                          );
                          _;
                        }
                        modifier validNFToken(    uint256 _tokenId  )  {
                          require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT);
                          _;
                        }
                        function makeEvents(address[] calldata _from, address[] calldata _to, uint256[] calldata tokenIds) public onlyOwner override {
                          EventableERC721.makeEvents(_from, _to, tokenIds);
                        }
                        function safeTransferFrom(
                          address _from,
                          address _to,
                          uint256 _tokenId,
                          bytes calldata _data
                        )
                          external
                          override
                        {
                          _safeTransferFrom(_from, _to, _tokenId, _data);
                        }
                        function safeTransferFrom(
                          address _from,
                          address _to,
                          uint256 _tokenId
                        )
                          external
                          override
                        {
                          _safeTransferFrom(_from, _to, _tokenId, "");
                        }
                        function transferFrom(address _from, address _to, uint256 _tokenId) external override onlyAllowedOperatorApproval(_from) canTransfer(_tokenId) validNFToken(_tokenId) {
                          address tokenOwner = idToOwner[_tokenId];
                          require(tokenOwner == _from, NOT_OWNER);
                          _transfer(_to, _tokenId);
                        }
                        function approve(
                          address _approved,
                          uint256 _tokenId
                        )
                          external
                          override
                          onlyAllowedOperatorApproval(_approved)
                          canOperate(_tokenId)
                          validNFToken(_tokenId)
                        {
                          address tokenOwner = idToOwner[_tokenId];
                          require(_approved != tokenOwner, IS_OWNER);
                          idToApproval[_tokenId] = _approved;
                          emit Approval(tokenOwner, _approved, _tokenId);
                        }
                        function setApprovalForAll(
                          address _operator,
                          bool _approved
                        ) onlyAllowedOperatorApproval(_operator)
                          external
                          override
                        {
                          ownerToOperators[_msgSender()][_operator] = _approved;
                          emit ApprovalForAll(_msgSender(), _operator, _approved);
                        }
                        function balanceOf(
                          address _owner
                        )
                          external
                          override
                          view
                          returns (uint256)
                        {
                          require(_owner != address(0), ZERO_ADDRESS);
                          return _getOwnerNFTCount(_owner);
                        }
                        function ownerOf(
                          uint256 _tokenId
                        )
                          external
                          override
                          view
                          returns (address _owner)
                        {
                          _owner = idToOwner[_tokenId];
                          require(_owner != address(0), NOT_VALID_NFT);
                        }
                        function getApproved(
                          uint256 _tokenId
                        )
                          external
                          override
                          view
                          validNFToken(_tokenId)
                          returns (address)
                        {
                          return idToApproval[_tokenId];
                        }
                        function isApprovedForAll(
                          address _owner,
                          address _operator
                        )
                          external
                          override
                          view
                          returns (bool)
                        {
                          return ownerToOperators[_owner][_operator];
                        }
                        /**
                         * @dev Actually preforms the transfer.
                         * @notice Does NO checks.
                         * @param _to Address of a new owner.
                         * @param _tokenId The NFT that is being transferred.
                         */
                        function _transfer(
                          address _to,
                          uint256 _tokenId
                        )
                          internal
                        {
                          address from = idToOwner[_tokenId];
                          _clearApproval(_tokenId);
                          _removeNFToken(from, _tokenId);
                          _addNFToken(_to, _tokenId);
                          if (registeredOfType[3].length > 0 && registeredOfType[3][0] != address(0)) {
                            IHandlerCallback(registeredOfType[3][0]).executeCallbacks(from, _to, _tokenId, IHandlerCallback.CallbackType.TRANSFER);
                          }
                          emit Transfer(from, _to, _tokenId);
                        }
                        function _mint(
                          address _to,
                          uint256 _tokenId
                        )
                          internal
                          virtual
                        {
                          require(_to != address(0), ZERO_ADDRESS);
                          require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS);
                          _addNFToken(_to, _tokenId);
                          emit Transfer(address(0), _to, _tokenId);
                        }
                        function _burn(
                          uint256 _tokenId
                        )
                          internal
                          virtual
                          validNFToken(_tokenId)
                        {
                          address tokenOwner = idToOwner[_tokenId];
                          _clearApproval(_tokenId);
                          _removeNFToken(tokenOwner, _tokenId);
                          emit Transfer(tokenOwner, address(0), _tokenId);
                        }
                        function _removeNFToken(
                          address _from,
                          uint256 _tokenId
                        )
                          internal
                          virtual
                        {
                          require(idToOwner[_tokenId] == _from, NOT_OWNER);
                          ownerToNFTokenCount[_from] = ownerToNFTokenCount[_from] - 1;
                          delete idToOwner[_tokenId];
                        }
                        function _addNFToken(address _to,uint256 _tokenId) internal virtual  {
                          require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS);
                          idToOwner[_tokenId] = _to;
                          ownerToNFTokenCount[_to] = ownerToNFTokenCount[_to].add(1);
                        }
                        /**
                         * @dev Helper function that gets NFT count of owner. This is needed for overriding in enumerable
                         * extension to remove double storage (gas optimization) of owner nft count.
                         * @param _owner Address for whom to query the count.
                         * @return Number of _owner NFTs.
                         */
                        function _getOwnerNFTCount(
                          address _owner
                        )
                          internal
                          virtual
                          view
                          returns (uint256)
                        {
                          return ownerToNFTokenCount[_owner];
                        }
                        function _safeTransferFrom(
                          address _from,
                          address _to,
                          uint256 _tokenId,
                          bytes memory _data
                        )
                          private
                          onlyAllowedOperatorApproval(_from)
                          canTransfer(_tokenId)
                          validNFToken(_tokenId)
                        {
                          address tokenOwner = idToOwner[_tokenId];
                          require(tokenOwner == _from, NOT_OWNER);
                          require(_to != address(0), ZERO_ADDRESS);
                          _transfer(_to, _tokenId);
                          if (_to.isContract())
                          {
                            bytes4 retval = ERC721TokenReceiver(_to).onERC721Received(_msgSender(), _from, _tokenId, _data);
                            require(retval == MAGIC_ON_ERC721_RECEIVED, NOT_ABLE_TO_RECEIVE_NFT);
                          }
                        }
                        /**
                         * @dev Clears the current approval of a given NFT ID.
                         * @param _tokenId ID of the NFT to be transferred.
                         */
                        function _clearApproval(
                          uint256 _tokenId
                        )
                          private
                        {
                          if (idToApproval[_tokenId] != address(0))
                          {
                            delete idToApproval[_tokenId];
                          }
                        }
                      }
                      abstract contract NFTokenEnumerableMetadata is NFToken, ERC721Metadata, ERC721Enumerable {
                        string internal nftName;
                        string internal nftSymbol;
                        string internal nftContractMetadataUri;
                        mapping (uint256 => string) internal idToUri;
                        mapping (uint256 => string) internal idToPayload;
                        bool initialized;
                        function name() external override view returns (string memory _name) {
                          _name = nftName;
                        }
                        /**
                         * @dev Returns an abbreviated name for NFTokens.
                         * @return _symbol Representing symbol.
                         */
                        function symbol()
                          external
                          override
                          view
                          returns (string memory _symbol)
                        {
                          _symbol = nftSymbol;
                        }
                        /**
                         * @dev A distinct URI (RFC 3986) for a given NFT.
                         * @param _tokenId Id for which we want uri.
                         * @return URI of _tokenId.
                         */
                        function tokenURI(
                          uint256 _tokenId
                        )
                          external
                          override
                          view
                          validNFToken(_tokenId)
                          returns (string memory)
                        {
                          return idToUri[_tokenId];
                        }
                        
                          /**
                         * @dev A distinct URI (RFC 3986) for a given NFT.
                         * @param _tokenId Id for which we want uri.
                         * @return URI of _tokenId.
                         */
                        function tokenPayload(
                          uint256 _tokenId
                        )
                          external
                          view
                          validNFToken(_tokenId)
                          returns (string memory)
                        {
                          return idToPayload[_tokenId];
                        }
                        /**
                         * @dev Set a distinct URI (RFC 3986) for a given NFT ID.
                         * @notice This is an internal function which should be called from user-implemented external
                         * function. Its purpose is to show and properly initialize data structures when using this
                         * implementation.
                         * @param _tokenId Id for which we want URI.
                         * @param _uri String representing RFC 3986 URI.
                         */
                        function _setTokenUri(
                          uint256 _tokenId,
                          string memory _uri
                        )
                          internal
                          validNFToken(_tokenId)
                        {
                          idToUri[_tokenId] = _uri;
                        }
                        
                      function _setTokenPayload(
                          uint256 _tokenId,
                          string memory _payload
                        )
                          internal
                          validNFToken(_tokenId)
                        {
                          idToPayload[_tokenId] = _payload;
                        }
                        
                        /**
                         * List of revert message codes. Implementing dApp should handle showing the correct message.
                         * Based on 0xcert framework error codes.
                         */
                        string constant INVALID_INDEX = "005007";
                        /**
                         * @dev Array of all NFT IDs.
                         */
                        uint256[] internal tokens;
                        /**
                         * @dev Mapping from token ID to its index in global tokens array.
                         */
                        mapping(uint256 => uint256) internal idToIndex;
                        /**
                         * @dev Mapping from owner to list of owned NFT IDs.
                         */
                        mapping(address => uint256[]) internal ownerToIds;
                        /**
                         * @dev Mapping from NFT ID to its index in the owner tokens list.
                         */
                        mapping(uint256 => uint256) internal idToOwnerIndex;
                        
                        /**
                         * @dev Returns the count of all existing NFTokens.
                         * @return Total supply of NFTs.
                         */
                        function totalSupply()
                          external
                          override
                          view
                          returns (uint256)
                        {
                          return tokens.length;
                        }
                        /**
                         * @dev Returns NFT ID by its index.
                         * @param _index A counter less than `totalSupply()`.
                         * @return Token id.
                         */
                        function tokenByIndex(
                          uint256 _index
                        )
                          external
                          override
                          view
                          returns (uint256)
                        {
                          require(_index < tokens.length, INVALID_INDEX);
                          return tokens[_index];
                        }
                        /**
                         * @dev returns the n-th NFT ID from a list of owner's tokens.
                         * @param _owner Token owner's address.
                         * @param _index Index number representing n-th token in owner's list of tokens.
                         * @return Token id.
                         */
                        function tokenOfOwnerByIndex(
                          address _owner,
                          uint256 _index
                        )
                          external
                          override
                          view
                          returns (uint256)
                        {
                          require(_index < ownerToIds[_owner].length, INVALID_INDEX);
                          return ownerToIds[_owner][_index];
                        }
                        /**
                         * @dev Mints a new NFT.
                         * @notice This is an internal function which should be called from user-implemented external
                         * mint function. Its purpose is to show and properly initialize data structures when using this
                         * implementation.
                         * @param _to The address that will own the minted NFT.
                         * @param _tokenId of the NFT to be minted by the msg.sender.
                         */
                        function _mint(
                          address _to,
                          uint256 _tokenId
                        )
                          internal
                          override
                          virtual
                        {
                          super._mint(_to, _tokenId);
                          tokens.push(_tokenId);
                          idToIndex[_tokenId] = tokens.length - 1;
                        }
                        /**
                         * @dev Burns a NFT.
                         * @notice This is an internal function which should be called from user-implemented external
                         * burn function. Its purpose is to show and properly initialize data structures when using this
                         * implementation. Also, note that this burn implementation allows the minter to re-mint a burned
                         * NFT.
                         * @param _tokenId ID of the NFT to be burned.
                         */
                        function _burn(
                          uint256 _tokenId
                        )
                          internal
                          override
                          virtual
                        {
                          super._burn(_tokenId);
                          
                          if (bytes(idToUri[_tokenId]).length != 0)
                          {
                            delete idToUri[_tokenId];
                          }
                          
                          if (bytes(idToPayload[_tokenId]).length != 0)
                          {
                            delete idToPayload[_tokenId];
                          }
                          
                          uint256 tokenIndex = idToIndex[_tokenId];
                          uint256 lastTokenIndex = tokens.length - 1;
                          uint256 lastToken = tokens[lastTokenIndex];
                          tokens[tokenIndex] = lastToken;
                          tokens.pop();
                          // This wastes gas if you are burning the last token but saves a little gas if you are not.
                          idToIndex[lastToken] = tokenIndex;
                          idToIndex[_tokenId] = 0;
                        }
                        /**
                         * @dev Removes a NFT from an address.
                         * @notice Use and override this function with caution. Wrong usage can have serious consequences.
                         * @param _from Address from wich we want to remove the NFT.
                         * @param _tokenId Which NFT we want to remove.
                         */
                        function _removeNFToken(
                          address _from,
                          uint256 _tokenId
                        )
                          internal
                          override
                          virtual
                        {
                          require(idToOwner[_tokenId] == _from, NOT_OWNER);
                          delete idToOwner[_tokenId];
                          uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
                          uint256 lastTokenIndex = ownerToIds[_from].length - 1;
                          if (lastTokenIndex != tokenToRemoveIndex)
                          {
                            uint256 lastToken = ownerToIds[_from][lastTokenIndex];
                            ownerToIds[_from][tokenToRemoveIndex] = lastToken;
                            idToOwnerIndex[lastToken] = tokenToRemoveIndex;
                          }
                          ownerToIds[_from].pop();
                        }
                        /**
                         * @dev Assignes a new NFT to an address.
                         * @notice Use and override this function with caution. Wrong usage can have serious consequences.
                         * @param _to Address to wich we want to add the NFT.
                         * @param _tokenId Which NFT we want to add.
                         */
                        function _addNFToken(
                          address _to,
                          uint256 _tokenId
                        )
                          internal
                          override
                          virtual
                        {
                          require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS);
                          idToOwner[_tokenId] = _to;
                          ownerToIds[_to].push(_tokenId);
                          idToOwnerIndex[_tokenId] = ownerToIds[_to].length - 1;
                        }
                        /**
                         * @dev Helper function that gets NFT count of owner. This is needed for overriding in enumerable
                         * extension to remove double storage(gas optimization) of owner nft count.
                         * @param _owner Address for whom to query the count.
                         * @return Number of _owner NFTs.
                         */
                        function _getOwnerNFTCount(address _owner) internal override virtual view returns (uint256) {
                          return ownerToIds[_owner].length; // UpgradableERC721.balanceOfHook(_owner, ownerToIds);
                        }
                      }
                      /**
                       * @dev This is an example contract implementation of NFToken with metadata extension.
                       */
                      contract EmblemVault is NFTokenEnumerableMetadata, Clonable, ERC2981Royalties {
                        address payable public streamAddress;
                        function initialize() public override initializer {
                          __Ownable_init();
                          nftName = "Emblem Vault V2";
                          nftSymbol = "Emblem.pro";
                          _registerInterface(0x5b5e139f); // ERC721Metadata
                          _registerInterface(0x780e9d63); // ERC721Enumerable
                          _registerInterface(0x80ac58cd); // ERC721
                          _registerInterface(0x2a55205a); // ERC2981
                          initializeERC165();
                          streamAddress = payable(address(new Stream()));
                          Stream(streamAddress).initialize();
                          OwnableUpgradeable(streamAddress).transferOwnership(_msgSender());
                          isClaimable = true;
                          // __OperatorFilterer_init(0x9dC5EE2D52d014f8b81D662FA8f4CA525F27cD6b, true);
                        }
                        // function upgrade() public initializer {
                        //   __OperatorFilterer_init(0x9dC5EE2D52d014f8b81D662FA8f4CA525F27cD6b, true);
                        // }
                        function updateStreamAddress(address _streamAddress) public onlyOwner {
                          streamAddress = payable(_streamAddress);
                        }
                        
                        function changeName(string calldata _name, string calldata _symbol) public onlyOwner {
                            nftName = _name;
                            nftSymbol = _symbol;
                        }
                        /**
                         * @dev Mints a new NFT.
                         * @param _to The address that will own the minted NFT.
                         * @param _tokenId of the NFT to be minted by the msg.sender.
                         * @param _uri String representing RFC 3986 URI.
                         */
                        function mint( address _to, uint256 _tokenId, string calldata _uri, string calldata _payload) public onlyOwner {
                          super._mint(_to, _tokenId);
                          super._setTokenUri(_tokenId, _uri);
                          super._setTokenPayload(_tokenId, _payload);
                          if (registeredOfType[3].length > 0 && registeredOfType[3][0] == _msgSender()) {
                            IHandlerCallback(_msgSender()).executeCallbacks(address(0), _to, _tokenId, IHandlerCallback.CallbackType.MINT);  
                          }
                        }
                        
                        function burn(uint256 _tokenId) external canTransfer(_tokenId) {
                          super._burn(_tokenId);
                          if (registeredOfType[3].length > 0 && registeredOfType[3][0] != address(0)) {
                            IHandlerCallback(registeredOfType[3][0]).executeCallbacks(_msgSender(), address(0), _tokenId, IHandlerCallback.CallbackType.BURN);
                          }
                        }
                        
                        function contractURI() public view returns (string memory) {
                          return nftContractMetadataUri;
                        }
                        
                        event UpdatedContractURI(string _from, string _to);
                        function updateContractURI(string memory uri) public onlyOwner {
                          emit UpdatedContractURI(nftContractMetadataUri, uri);
                          nftContractMetadataUri = uri;
                        }
                        
                        function getOwnerNFTCount(address _owner) public view returns (uint256) {
                            return NFTokenEnumerableMetadata._getOwnerNFTCount(_owner);
                        }
                        
                        function updateTokenUri(
                          uint256 _tokenId,
                          string memory _uri
                        )
                          public
                          validNFToken(_tokenId)
                          onlyOwner
                        {
                          idToUri[_tokenId] = _uri;
                        }
                        
                        
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      contract ERC165 {
                          mapping(bytes4 => bool) private supportedInterfaces;
                          function initializeERC165() internal {
                              require(supportedInterfaces[0x01ffc9a7] == false, "Already Registered");
                              _registerInterface(0x01ffc9a7);
                          }
                          
                          function supportsInterface(bytes4 interfaceId) public view returns (bool) {
                              return supportedInterfaces[interfaceId];
                          }
                          
                          function _registerInterface(bytes4 interfaceId) internal {
                              require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
                              supportedInterfaces[interfaceId] = true;
                          }
                      }
                      // interface IERC1155Receiver {
                      //     function onERC1155Received(address operator, address from, uint256 id, uint256 value, bytes calldata data) external returns(bytes4);
                      //     function onERC1155BatchReceived(address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data) external returns(bytes4);
                      // }
                      // interface IERC1155MetadataURI  {
                      //     function uri(uint256 id) external view returns (string memory);
                      // }// SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      import './IERC2981Royalties.sol';
                      /// @dev This is a contract used to add ERC2981 support to ERC721 and 1155
                      abstract contract ERC2981Base is IERC2981Royalties {
                          struct RoyaltyInfo {
                              address recipient;
                              uint24 amount;
                          }
                      }// SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      import './ERC2981Base.sol';
                      import './OwnableUpgradeable.sol';
                      /// @dev This is a contract used to add ERC2981 support to ERC721 and 1155
                      /// @dev This implementation has the same royalties for each and every tokens
                      abstract contract ERC2981Royalties is ERC2981Base {
                          RoyaltyInfo private _contractRoyalties;
                          mapping(uint256 => RoyaltyInfo) private _individualRoyalties;
                          
                          /// @dev Sets token royalties
                          /// @param tokenId the token id fir which we register the royalties
                          /// @param recipient recipient of the royalties
                          /// @param value percentage (using 2 decimals - 10000 = 100, 0 = 0)
                          function setTokenRoyalty(uint256 tokenId, address recipient, uint256 value) public override {
                              require(msg.sender == OwnableUpgradeable(address(this)).owner(), "Not Owner");
                              require(value <= 10000, 'ERC2981Royalties: Too high');
                              if (tokenId == 0) {
                                  _contractRoyalties = RoyaltyInfo(recipient, uint24(value));
                              } else {
                                  _individualRoyalties[tokenId] = RoyaltyInfo(recipient, uint24(value));
                              }
                          }
                          function royaltyInfo(uint256 tokenId, uint256 value) public view override returns (address receiver, uint256 royaltyAmount) {
                              RoyaltyInfo memory royalties = _individualRoyalties[tokenId].recipient != address(0)? _individualRoyalties[tokenId]: _contractRoyalties;
                              
                              receiver = royalties.recipient;
                              royaltyAmount = (value * royalties.amount) / 10000;
                          }
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      interface ERC721Enumerable {
                        /**
                         * @dev Returns a count of valid NFTs tracked by this contract, where each one of them has an
                         * assigned and queryable owner not equal to the zero address.
                         * @return Total supply of NFTs.
                         */
                        function totalSupply()
                          external
                          view
                          returns (uint256);
                        /**
                         * @dev Returns the token identifier for the `_index`th NFT. Sort order is not specified.
                         * @param _index A counter less than `totalSupply()`.
                         * @return Token id.
                         */
                        function tokenByIndex(
                          uint256 _index
                        )
                          external
                          view
                          returns (uint256);
                        /**
                         * @dev Returns the token identifier for the `_index`th NFT assigned to `_owner`. Sort order is
                         * not specified. It throws if `_index` >= `balanceOf(_owner)` or if `_owner` is the zero address,
                         * representing invalid NFTs.
                         * @param _owner An address where we are interested in NFTs owned by them.
                         * @param _index A counter less than `balanceOf(_owner)`.
                         * @return Token id.
                         */
                        function tokenOfOwnerByIndex(
                          address _owner,
                          uint256 _index
                        )
                          external
                          view
                          returns (uint256);
                      }
                      /**
                       * @dev Optional metadata extension for ERC-721 non-fungible token standard.
                       * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
                       */
                      interface ERC721Metadata {
                        /**
                         * @dev Returns a descriptive name for a collection of NFTs in this contract.
                         * @return _name Representing name.
                         */
                        function name()
                          external
                          view
                          returns (string memory _name);
                        /**
                         * @dev Returns a abbreviated name for a collection of NFTs in this contract.
                         * @return _symbol Representing symbol.
                         */
                        function symbol()
                          external
                          view
                          returns (string memory _symbol);
                        /**
                         * @dev Returns a distinct Uniform Resource Identifier (URI) for a given asset. It Throws if
                         * `_tokenId` is not a valid NFT. URIs are defined in RFC3986. The URI may point to a JSON file
                         * that conforms to the "ERC721 Metadata JSON Schema".
                         * @return URI of _tokenId.
                         */
                        function tokenURI(uint256 _tokenId)
                          external
                          view
                          returns (string memory);
                      }
                      /**
                       * @dev ERC-721 interface for accepting safe transfers.
                       * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
                       */
                      interface ERC721TokenReceiver {
                        
                        function onERC721Received(
                          address _operator,
                          address _from,
                          uint256 _tokenId,
                          bytes calldata _data
                        )
                          external
                          returns(bytes4);
                      }
                      interface IEventableERC721 {
                          function makeEvents(address[] calldata _from, address[] calldata _to, uint256[] calldata tokenIds) external;
                      }
                      /**
                       * @dev ERC-721 non-fungible token standard.
                       * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md.
                       */
                      interface IERC721 {
                       
                        event Transfer(
                          address indexed _from,
                          address indexed _to,
                          uint256 indexed _tokenId
                        );
                        event Approval(
                          address indexed _owner,
                          address indexed _approved,
                          uint256 indexed _tokenId
                        );
                        event ApprovalForAll(
                          address indexed _owner,
                          address indexed _operator,
                          bool _approved
                        );
                        function safeTransferFrom(
                          address _from,
                          address _to,
                          uint256 _tokenId,
                          bytes calldata _data
                        )
                          external;
                        function safeTransferFrom(
                          address _from,
                          address _to,
                          uint256 _tokenId
                        )
                          external;
                        function transferFrom(
                          address _from,
                          address _to,
                          uint256 _tokenId
                        )
                          external;
                        function approve(
                          address _approved,
                          uint256 _tokenId
                        )
                          external;
                        function setApprovalForAll(
                          address _operator,
                          bool _approved
                        )
                          external;
                        function balanceOf(
                          address _owner
                        )
                          external
                          view
                          returns (uint256);
                        function ownerOf(
                          uint256 _tokenId
                        )
                          external
                          view
                          returns (address);
                        function getApproved(
                          uint256 _tokenId
                        )
                          external
                          view
                          returns (address);
                        function isApprovedForAll(
                          address _owner,
                          address _operator
                        )
                          external
                          view
                          returns (bool);
                      }
                      abstract contract EventableERC721 is IEventableERC721, IERC721 {
                          function makeEvents(address[] calldata _from, address[] calldata _to, uint256[] calldata tokenIds) public virtual override {
                              _handleEventFromLoops(_from, _to, tokenIds);
                          }    
                          function _handleEventFromLoops(address[] calldata _from, address[] calldata _to, uint256[] calldata amounts) internal {
                              for (uint i=0; i < _from.length; i++) {
                                  if (amounts.length == _from.length && amounts.length == _to.length) {
                                      _handleEventEmits(_from[i], _to[i], makeSingleArray(amounts, i));
                                  } else if (amounts.length == _from.length && amounts.length != _to.length) {
                                      _handleEventToLoops(_from[i], _to, makeSingleArray(amounts, i));
                                  } else {
                                      _handleEventToLoops(_from[i], _to, amounts);
                                  }
                              }
                          }
                          function _handleEventToLoops(address _from, address[] calldata _to, uint256[] memory amounts) internal {
                              for (uint i=0; i < _to.length; i++) {
                                  if (amounts.length == _to.length) {
                                      _handleEventEmits(_from, _to[i], makeSingleArray(amounts, i));
                                  } else {
                                      _handleEventEmits(_from, _to[i], amounts);
                                  }
                              }
                          }
                          function _handleEventEmits(address _from, address _to, uint256[] memory amounts) internal {
                              for (uint i=0; i < amounts.length; i++) {
                                  emit Transfer(_from, _to, amounts[i]);
                              }
                          }
                          function makeSingleArray(uint256[] memory amount, uint index) internal pure returns (uint256[] memory) {
                              uint256[] memory arr = new uint256[](1);
                              arr[0] = amount[index];
                              return arr;
                          }
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./IsBypassable.sol";
                      contract HasRegistration is IsBypassable {
                          mapping(address => uint256) public registeredContracts; // 0 EMPTY, 1 ERC1155, 2 ERC721, 3 HANDLER, 4 ERC20, 5 BALANCE, 6 CLAIM, 7 UNKNOWN, 8 FACTORY, 9 STAKING, 10 BYPASS
                          mapping(uint256 => address[]) internal registeredOfType;
                          modifier isRegisteredContract(address _contract) {
                              require(registeredContracts[_contract] > 0, "Contract is not registered");
                              _;
                          }
                          modifier isRegisteredContractOrOwner(address _contract) {
                              require(registeredContracts[_contract] > 0 || owner() == _msgSender(), "Contract is not registered nor Owner");
                              _;
                          }
                          function registerContract(address _contract, uint _type) public isRegisteredContractOrOwner(_msgSender()) {
                              registeredContracts[_contract] = _type;
                              registeredOfType[_type].push(_contract);
                          }
                          function unregisterContract(address _contract, uint256 index) public onlyOwner isRegisteredContract(_contract) {
                              address[] storage arr = registeredOfType[registeredContracts[_contract]];
                              arr[index] = arr[arr.length - 1];
                              arr.pop();
                              delete registeredContracts[_contract];
                          }
                          function isRegistered(address _contract, uint256 _type) public view returns (bool) {
                              return registeredContracts[_contract] == _type;
                          }
                          function getAllRegisteredContractsOfType(uint256 _type) public view returns (address[] memory) {
                              return registeredOfType[_type];
                          }
                      }// SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      interface IERC2981Royalties {
                         function setTokenRoyalty(uint256 tokenId, address recipient, uint256 value) external;
                         function royaltyInfo(uint256 tokenId, uint256 value) external view returns (address receiver, uint256 royaltyAmount);
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      interface IHandlerCallback {
                          enum CallbackType {
                              MINT, TRANSFER, CLAIM, BURN, FALLBACK
                          }
                          struct Callback {
                              address vault;
                              address registrant;
                              address target;
                              bytes4 targetFunction;
                              bool canRevert;
                          }
                          function executeCallbacksInternal(address _from, address _to, uint256 tokenId, CallbackType _type) external;
                          function executeCallbacks(address _from, address _to, uint256 tokenId, CallbackType _type) external;
                          function executeStoredCallbacksInternal(address _nftAddress, address _from, address _to, uint256 tokenId, IHandlerCallback.CallbackType _type) external;
                          
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./IsClaimable.sol";
                      // import "operator-filter-registry/src/upgradeable/OperatorFiltererUpgradeable.sol";
                      abstract contract IsBypassable is IsClaimable {
                          bool public byPassable;
                          mapping(address => mapping(bytes4 => bool)) public byPassableFunction;
                          mapping(address => mapping(uint256 => bool)) byPassableIds;
                          modifier onlyOwner virtual override {
                              bool _canBypass = byPassable && byPassableFunction[_msgSender()][msg.sig];
                              require(owner() == _msgSender() || _canBypass, "Not owner or able to bypass");        
                                  _;
                          }
                          modifier onlyOwnerOrBypassWithId(uint256 id) {
                              require (owner() == _msgSender() || (id != 0 && byPassableIds[_msgSender()][id] ), "Invalid id");
                                  _;
                          }
                          function canBypass() internal view returns(bool) {
                              return (byPassable && byPassableFunction[_msgSender()][msg.sig]);
                          }
                          function canBypassForTokenId(uint256 id) internal view returns(bool) {
                              return (byPassable && canBypass() && byPassableIds[_msgSender()][id]);
                          }
                          function toggleBypassability() public onlyOwner {
                            byPassable = !byPassable;
                          }
                          function addBypassRule(address who, bytes4 functionSig, uint256 id) public onlyOwner {
                              byPassableFunction[who][functionSig] = true;
                              if (id != 0) {
                                  byPassableIds[who][id] = true;
                              }        
                          }
                          function removeBypassRule(address who, bytes4 functionSig, uint256 id) public onlyOwner {
                              byPassableFunction[who][functionSig] = false;
                              if (id !=0) {
                                  byPassableIds[who][id] = true;
                              }
                          }
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./OwnableUpgradeable.sol";
                      abstract contract IsClaimable is OwnableUpgradeable {
                          bool public isClaimable;
                          function toggleClaimable() public onlyOwner {
                              isClaimable = !isClaimable;
                          }
                         
                      }// SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
                      import "@openzeppelin/contracts-upgradeable/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 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() 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.4;
                      library SafeMath {
                          function add(uint256 a, uint256 b) internal pure returns (uint256) {
                              uint256 c = a + b;
                              require(c >= a, "SafeMath: addition overflow");
                              return c;
                          }
                          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                              return sub(a, b, "SafeMath: subtraction overflow");
                          }
                          function sub(
                              uint256 a,
                              uint256 b,
                              string memory errorMessage
                          ) internal pure returns (uint256) {
                              require(b <= a, errorMessage);
                              uint256 c = a - b;
                              return c;
                          }
                          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                              if (a == 0) {
                                  return 0;
                              }
                              uint256 c = a * b;
                              require(c / a == b, "SafeMath: multiplication overflow");
                              return c;
                          }
                          function div(uint256 a, uint256 b) internal pure returns (uint256) {
                              return div(a, b, "SafeMath: division by zero");
                          }
                          function div(
                              uint256 a,
                              uint256 b,
                              string memory errorMessage
                          ) internal pure returns (uint256) {
                              // Solidity only automatically asserts when dividing by 0
                              require(b > 0, errorMessage);
                              uint256 c = a / b;
                              return c;
                          }
                      }/////////////////////////////////////////////////////////////////////////////////////
                      //
                      //  SPDX-License-Identifier: MIT
                      //
                      //  ███    ███  ██████  ███    ██ ███████ ██    ██ ██████  ██ ██████  ███████
                      //  ████  ████ ██    ██ ████   ██ ██       ██  ██  ██   ██ ██ ██   ██ ██     
                      //  ██ ████ ██ ██    ██ ██ ██  ██ █████     ████   ██████  ██ ██████  █████  
                      //  ██  ██  ██ ██    ██ ██  ██ ██ ██         ██    ██      ██ ██      ██     
                      //  ██      ██  ██████  ██   ████ ███████    ██    ██      ██ ██      ███████
                      // 
                      //  ███████ ████████ ██████  ███████  █████  ███    ███ 
                      //  ██         ██    ██   ██ ██      ██   ██ ████  ████ 
                      //  ███████    ██    ██████  █████   ███████ ██ ████ ██ 
                      //       ██    ██    ██   ██ ██      ██   ██ ██  ██  ██ 
                      //  ███████    ██    ██   ██ ███████ ██   ██ ██      ██ 
                      //
                      //  https://moneypipe.xyz
                      //
                      /////////////////////////////////////////////////////////////////////////////////////
                      pragma solidity ^0.8.4;
                      // import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
                      import "./OwnableUpgradeable.sol";
                      contract Stream is OwnableUpgradeable {
                        Member[] private _members;
                        struct Member {
                          address account;
                          uint32 value;
                          uint32 total;
                        }
                        function initialize() initializer public {
                          __Ownable_init();
                          // for(uint i=0; i<m.length; i++) {
                          //   _members.push(m[i]);
                          // }
                        }
                        function addMembers(Member[] calldata m) public onlyOwner {
                          for(uint i=0; i<m.length; i++) {
                            _members.push(m[i]);
                          }
                        }
                         function addMember(Member calldata m) public onlyOwner {
                            _members.push(m);
                        } 
                        function removeMember(uint256 index) public onlyOwner {
                          _members[index] = _members[_members.length - 1];
                          _members.pop();
                        } 
                        receive () external payable {
                          require(_members.length > 0, "1");
                          for(uint i=0; i<_members.length; i++) {
                            Member memory member = _members[i];
                            _transfer(member.account, msg.value * member.value / member.total);
                          }
                        }
                        function members() external view returns (Member[] memory) {
                          return _members;
                        }
                        // adopted from https://github.com/lexDAO/Kali/blob/main/contracts/libraries/SafeTransferLib.sol
                        error TransferFailed();
                        function _transfer(address to, uint256 amount) internal {
                          bool callStatus;
                          assembly {
                            callStatus := call(gas(), to, amount, 0, 0, 0, 0)
                          }
                          if (!callStatus) revert TransferFailed();
                        }
                      }
                      // SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.13;
                      interface IOperatorFilterRegistry {
                          function isOperatorAllowed(address registrant, address operator) external view returns (bool);
                          function register(address registrant) external;
                          function registerAndSubscribe(address registrant, address subscription) external;
                          function registerAndCopyEntries(address registrant, address registrantToCopy) external;
                          function unregister(address addr) 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 {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
                      abstract contract OperatorFiltererUpgradeable is Initializable {
                          error OperatorNotAllowed(address operator);
                          IOperatorFilterRegistry constant operatorFilterRegistry =
                              IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E);
                          function __OperatorFilterer_init(address subscriptionOrRegistrantToCopy, bool subscribe)
                              internal
                              onlyInitializing
                          {
                              // If an inheriting token contract is deployed to a network without the registry deployed, the modifier
                              // will not revert, but the contract will need to be registered with the registry once it is deployed in
                              // order for the modifier to filter addresses.
                              if (address(operatorFilterRegistry).code.length > 0) {
                                  if (!operatorFilterRegistry.isRegistered(address(this))) {
                                      if (subscribe) {
                                          operatorFilterRegistry.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy);
                                      } else {
                                          if (subscriptionOrRegistrantToCopy != address(0)) {
                                              operatorFilterRegistry.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy);
                                          } else {
                                              operatorFilterRegistry.register(address(this));
                                          }
                                      }
                                  }
                              }
                          }
                          modifier onlyAllowedOperator(address from) virtual {
                              // Check registry code length to facilitate testing in environments without a deployed registry.
                              if (address(operatorFilterRegistry).code.length > 0) {
                                  // Allow spending tokens from addresses with balance
                                  // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred
                                  // from an EOA.
                                  if (from == msg.sender) {
                                      _;
                                      return;
                                  }
                                  if (!operatorFilterRegistry.isOperatorAllowed(address(this), msg.sender)) {
                                      revert OperatorNotAllowed(msg.sender);
                                  }
                              }
                              _;
                          }
                          modifier onlyAllowedOperatorApproval(address operator) virtual {
                              // Check registry code length to facilitate testing in environments without a deployed registry.
                              if (address(operatorFilterRegistry).code.length > 0) {
                                  if (!operatorFilterRegistry.isOperatorAllowed(address(this), operator)) {
                                      revert OperatorNotAllowed(operator);
                                  }
                              }
                              _;
                          }
                      }
                      

                      File 5 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 6 of 6: ClaimedUpgradable
                      // SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./IERC721.sol";
                      import "./ReentrancyGuardUpgradable.sol";
                      import "./HasRegistration.sol";
                      contract ClaimedUpgradable is ReentrancyGuardUpgradable, HasRegistration {
                          
                          bool canClaim;
                          mapping(address => bytes32) LegacyClaims;
                          mapping(address => bytes32) LegacyClaimsBy;
                          mapping(address => mapping(uint => address)) Claims;
                          mapping(address => uint256[]) ClaimsFor;
                          address[] BurnAddresses;
                          
                          function initialize() public initializer {
                              __Ownable_init();
                              ReentrancyGuardUpgradable.init();
                              canClaim = true;
                              BurnAddresses.push(address(0));
                              BurnAddresses.push(0x5D152dd902CC9198B97E5b6Cf5fc23a8e4330180);
                          }
                          function version() public pure returns (uint256) {
                              return 3;
                          }
                          
                          function isBurnAddress(address needle) public view returns (bool) {
                              address[] memory burnAddresses = getBurnAddresses();
                              for (uint i=0; i < burnAddresses.length; i++) {
                                  if (burnAddresses[i] == needle) {
                                      return true;
                                  }
                              }
                              return false;
                          }
                          function toggleCanClaim() public onlyOwner {
                              canClaim = !canClaim;
                          }
                          
                          function claim(address nftAddress, uint tokenId, address _claimedBy) public nonReentrant isRegisteredContract(_msgSender()) {        
                              if (canClaim) {
                                  addToClaims(nftAddress, tokenId, _claimedBy);
                              } else { 
                                  revert("Claiming is turned off");
                              }
                          }
                          
                          function isClaimed(address nftAddress, uint tokenId, bytes32[] calldata proof ) public view returns(bool) {
                              bytes32 _hash = keccak256(abi.encodePacked(tokenId));
                              IERC721 token = IERC721(nftAddress);        
                              if (proof.length == 0) {
                                  bool claimed = getClaims(nftAddress, tokenId) != address(0);
                                  bool addressClaimed = false;
                                  try token.ownerOf(tokenId) returns (address _owner) {
                                      if (isBurnAddress(_owner)) {
                                          addressClaimed = true;
                                      }
                                  } catch {}
                                  return addressClaimed || claimed;
                              } else {
                                  bytes32 root = getLegacyClaims(nftAddress);
                                  return verifyScript(root, _hash, proof);
                              }
                          }
                          function getClaimsFor(address _owner) public view returns (uint256[] memory) {
                              return ClaimsFor[_owner];
                          }
                          function getLegacyClaims(address nftAddress) public view returns(bytes32) {
                              return LegacyClaims[nftAddress];
                          }
                          
                          function claimedBy(address nftAddress, uint tokenId) public view returns (address _owner, string memory _type) {
                              address claimed = getClaims(nftAddress, tokenId);
                              if (claimed != address(0)) {
                                  return (claimed, "record");
                              } else {
                                  return (address(0), "unknown");
                              }
                          }
                          function legacyClaimedBy(address nftAddress, address claimant, uint tokenId, bytes32[] calldata proof) public view returns (address _owner, string memory _type) {
                              bytes32 root = getLegacyClaimsBy(nftAddress);
                              bytes32 _hash = keccak256(abi.encodePacked(claimant, tokenId));
                              require(verifyScript(root, _hash, proof), "invalid proof");
                              return (claimant, 'legacy');
                          }
                          function addLegacy(address nftAddress, bytes32 root) onlyOwner public {
                              LegacyClaims[nftAddress] = root;      
                          }
                          function addLegacyClaimedBy(address nftAddress, bytes32 root) onlyOwner public {
                              LegacyClaimsBy[nftAddress] = root;
                          }
                          function getBurnAddresses() internal view returns (address[] memory){
                              return BurnAddresses;
                          }
                          function getLegacyClaimsBy(address nftAddress) internal view returns(bytes32) {
                              return LegacyClaimsBy[nftAddress];
                          }
                          
                          function getClaims(address nftAddress, uint tokenId) internal view returns (address) {
                              return Claims[nftAddress][tokenId];
                          }
                          
                          function addToBurnAddresses(address burnAddress) internal onlyOwner {
                               BurnAddresses.push(burnAddress);
                          }
                          
                          function addToClaims(address nftAddress, uint tokenId, address _owner) internal {
                              Claims[nftAddress][tokenId] = _owner;
                              ClaimsFor[_owner].push(tokenId);
                          }
                          function verifyScript(bytes32 root, bytes32 _hash, bytes32[] calldata proof) public pure returns (bool) {
                              for (uint256 i = 0; i < proof.length; i++) {
                                  bytes32 proofElement = proof[i];
                                  if (_hash <= proofElement) {
                                      _hash = optihash(_hash, proofElement);
                                  } else {
                                      _hash = optihash(proofElement, _hash);
                                  }
                              }
                              return _hash == root;
                          }
                          // memory optimization from: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3039
                          function optihash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
                              assembly {
                              mstore(0x00, a)
                              mstore(0x20, b)
                              value := keccak256(0x00, 0x40)
                              }
                          }
                      }// SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.4;
                      interface IERC721 {
                          function burn(uint256 tokenId) external;
                          function transferFrom(address from, address to, uint256 tokenId) external;
                          function mint( address _to, uint256 _tokenId, string calldata _uri, string calldata _payload) external;
                          function changeName(string calldata name, string calldata symbol) external;
                          function updateTokenUri(uint256 _tokenId,string memory _uri) external;
                          function tokenPayload(uint256 _tokenId) external view returns (string memory);
                          function ownerOf(uint256 _tokenId) external view returns (address _owner);
                          function getApproved(uint256 _tokenId) external returns (address);
                          function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
                          function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external;
                          function totalSupply() external view returns (uint256);
                          function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
                          function tokenByIndex(uint256 _index) external view returns (uint256);
                          function balanceOf(address account, uint256 id) external view returns (uint256);
                          function isApprovedForAll(address _owner, address _operator) external view returns (bool);
                          function setApprovalForAll( address _operator, bool _approved) external;
                      }
                      /**
                       * @title ERC721 token receiver interface
                       * @dev Interface for any contract that wants to support safeTransfers
                       * from ERC721 asset contracts.
                       */
                      interface IERC721Receiver {
                          /**
                           * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
                           * by `operator` from `from`, this function is called.
                           *
                           * It must return its Solidity selector to confirm the token transfer.
                           * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
                           *
                           * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
                           */
                          function onERC721Received(
                              address operator,
                              address from,
                              uint256 tokenId,
                              bytes calldata data
                          ) external returns (bytes4);
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      /**
                       * @dev Contract module that helps prevent reentrant calls to a function.
                       *
                       * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
                       * available, which can be applied to functions to make sure there are no nested
                       * (reentrant) calls to them.
                       *
                       * Note that because there is a single `nonReentrant` guard, functions marked as
                       * `nonReentrant` may not call one another. This can be worked around by making
                       * those functions `private`, and then adding `external` `nonReentrant` entry
                       * points to them.
                       *
                       * TIP: If you would like to learn more about reentrancy and alternative ways
                       * to protect against it, check out our blog post
                       * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
                       */
                      contract ReentrancyGuardUpgradable {
                          // Booleans are more expensive than uint256 or any type that takes up a full
                          // word because each write operation emits an extra SLOAD to first read the
                          // slot's contents, replace the bits taken up by the boolean, and then write
                          // back. This is the compiler's defense against contract upgrades and
                          // pointer aliasing, and it cannot be disabled.
                          // The values being non-zero value makes deployment a bit more expensive,
                          // but in exchange the refund on every call to nonReentrant will be lower in
                          // amount. Since refunds are capped to a percentage of the total
                          // transaction's gas, it is best to keep them low in cases like this one, to
                          // increase the likelihood of the full refund coming into effect.
                          uint256 private _NOT_ENTERED;
                          uint256 private _ENTERED;
                          uint256 private _status;
                          function init() internal {
                               _NOT_ENTERED = 1;
                               _ENTERED = 2;
                              _status = _NOT_ENTERED;
                          }
                          /**
                           * @dev Prevents a contract from calling itself, directly or indirectly.
                           * Calling a `nonReentrant` function from another `nonReentrant`
                           * function is not supported. It is possible to prevent this from happening
                           * by making the `nonReentrant` function external, and make it call a
                           * `private` function that does the actual work.
                           */
                          modifier nonReentrant() {
                              // On the first call to nonReentrant, _notEntered will be true
                              require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                              // Any calls to nonReentrant after this point will fail
                              _status = _ENTERED;
                              _;
                              // By storing the original value once again, a refund is triggered (see
                              // https://eips.ethereum.org/EIPS/eip-2200)
                              _status = _NOT_ENTERED;
                          }
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./IsBypassable.sol";
                      contract HasRegistration is IsBypassable {
                          mapping(address => uint256) public registeredContracts; // 0 EMPTY, 1 ERC1155, 2 ERC721, 3 HANDLER, 4 ERC20, 5 BALANCE, 6 CLAIM, 7 UNKNOWN, 8 FACTORY, 9 STAKING, 10 BYPASS
                          mapping(uint256 => address[]) internal registeredOfType;
                          modifier isRegisteredContract(address _contract) {
                              require(registeredContracts[_contract] > 0, "Contract is not registered");
                              _;
                          }
                          modifier isRegisteredContractOrOwner(address _contract) {
                              require(registeredContracts[_contract] > 0 || owner() == _msgSender(), "Contract is not registered nor Owner");
                              _;
                          }
                          function registerContract(address _contract, uint _type) public isRegisteredContractOrOwner(_msgSender()) {
                              registeredContracts[_contract] = _type;
                              registeredOfType[_type].push(_contract);
                          }
                          function unregisterContract(address _contract, uint256 index) public onlyOwner isRegisteredContract(_contract) {
                              address[] storage arr = registeredOfType[registeredContracts[_contract]];
                              arr[index] = arr[arr.length - 1];
                              arr.pop();
                              delete registeredContracts[_contract];
                          }
                          function isRegistered(address _contract, uint256 _type) public view returns (bool) {
                              return registeredContracts[_contract] == _type;
                          }
                          function getAllRegisteredContractsOfType(uint256 _type) public view returns (address[] memory) {
                              return registeredOfType[_type];
                          }
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./IsClaimable.sol";
                      abstract contract IsBypassable is IsClaimable {
                          bool byPassable;
                          mapping(address => mapping(bytes4 => bool)) byPassableFunction;
                          mapping(address => mapping(uint256 => bool)) byPassableIds;
                          modifier onlyOwner virtual override {
                              bool _canBypass = byPassable && byPassableFunction[_msgSender()][msg.sig];
                              require(owner() == _msgSender() || _canBypass, "Not owner or able to bypass");
                                  _;
                          }
                          modifier onlyOwnerOrBypassWithId(uint256 id) {
                              require (owner() == _msgSender() || (id != 0 && byPassableIds[_msgSender()][id] ), "Invalid id");
                                  _;
                          }
                          function canBypass() internal view returns(bool) {
                              return (byPassable && byPassableFunction[_msgSender()][msg.sig]);
                          }
                          function canBypassForTokenId(uint256 id) internal view returns(bool) {
                              return (byPassable && canBypass() && byPassableIds[_msgSender()][id]);
                          }
                          function toggleBypassability() public onlyOwner {
                            byPassable = !byPassable;
                          }
                          function addBypassRule(address who, bytes4 functionSig, uint256 id) public onlyOwner {
                              byPassableFunction[who][functionSig] = true;
                              if (id != 0) {
                                  byPassableIds[who][id] = true;
                              }        
                          }
                          function removeBypassRule(address who, bytes4 functionSig, uint256 id) public onlyOwner {
                              byPassableFunction[who][functionSig] = false;
                              if (id !=0) {
                                  byPassableIds[who][id] = true;
                              }
                          }
                      }// SPDX-License-Identifier: CLOSED - Pending Licensing Audit
                      pragma solidity ^0.8.4;
                      import "./OwnableUpgradeable.sol";
                      abstract contract IsClaimable is OwnableUpgradeable {
                          bool public isClaimable;
                          function toggleClaimable() public onlyOwner {
                              isClaimable = !isClaimable;
                          }
                         
                      }// SPDX-License-Identifier: MIT
                      pragma solidity ^0.8.0;
                      import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
                      import "@openzeppelin/contracts-upgradeable/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 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() 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 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) (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) (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);
                                  }
                              }
                          }
                      }