ETH Price: $2,486.54 (-2.77%)

Transaction Decoder

Block:
17960253 at Aug-21-2023 02:53:35 AM +UTC
Transaction Fee:
0.003740736426636364 ETH $9.30
Gas Used:
307,772 Gas / 12.154245437 Gwei

Emitted Events:

555 TWCloneFactory.ProxyDeployed( implementation=AirdropERC721, proxy=AirdropERC721, deployer=[Sender] 0xa701e513c7b8071608d152d6138c8d3ca932cea3 )
556 AirdropERC721.ContractURIUpdated( prevURI=, newURI=ipfs://QmbAYXCb6d31Q5PjdqaXjNGG7og1fRtob649ZTZMXLYM68/0 )
557 AirdropERC721.RoleGranted( role=0000000000000000000000000000000000000000000000000000000000000000, account=[Sender] 0xa701e513c7b8071608d152d6138c8d3ca932cea3, sender=[Receiver] TWCloneFactory )
558 AirdropERC721.Initialized( version=1 )

Account State Difference:

  Address   Before After State Difference Code
0x2E50B51a...7812c1C44
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 497590261154554171967156966156626675044361416685740010185735068046189125167375356484112012258427277393353715
(MEV Builder: 0x563...cf3)
48.293220502105260651 Eth48.293251279305260651 Eth0.0000307772
0x76F948E5...Bf524805E
0xa701e513...cA932cEA3
0.029423905661525825 Eth
Nonce: 6
0.025683169234889461 Eth
Nonce: 7
0.003740736426636364

Execution Trace

TWCloneFactory.deployProxyByImplementation( _implementation=0x74F13914DA24e94B15E12879fA969B345D3a4387, _data=0x3A105CFB000000000000000000000000A701E513C7B8071608D152D6138C8D3CA932CEA3000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000C00000000000000000000000000000000000000000000000000000000000000037697066733A2F2F516D624159584362366433315135506A647161586A4E4747376F67316652746F623634395A545A4D584C594D36382F300000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000C82BBE41F2CF04E3A8EFA18F7032BDD7F6D98A8100000000000000000000000084A0856B038EAAD1CC7E297CF34A7E72685A8693, _salt=3137393630323530000000000000000000000000000000000000000000000000 ) => ( deployedProxy=0x2E50B51a858bD8a5f43BeEC6070F3627812c1C44 )
  • AirdropERC721.3d602d80( )
  • AirdropERC721.initialize( _defaultAdmin=0xa701e513C7b8071608D152d6138C8D3cA932cEA3, _contractURI=ipfs://QmbAYXCb6d31Q5PjdqaXjNGG7og1fRtob649ZTZMXLYM68/0, _trustedForwarders=[0xc82BbE41f2cF04e3a8efA18F7032BDD7f6d98a81, 0x84a0856b038eaAd1cC7E297cF34A7e72685A8693] )
    • AirdropERC721.initialize( _defaultAdmin=0xa701e513C7b8071608D152d6138C8D3cA932cEA3, _contractURI=ipfs://QmbAYXCb6d31Q5PjdqaXjNGG7og1fRtob649ZTZMXLYM68/0, _trustedForwarders=[0xc82BbE41f2cF04e3a8efA18F7032BDD7f6d98a81, 0x84a0856b038eaAd1cC7E297cF34A7e72685A8693] )
      File 1 of 3: TWCloneFactory
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.11;
      /// @author thirdweb
      //   $$\\     $$\\       $$\\                 $$\\                         $$\\
      //   $$ |    $$ |      \\__|                $$ |                        $$ |
      // $$$$$$\\   $$$$$$$\\  $$\\  $$$$$$\\   $$$$$$$ |$$\\  $$\\  $$\\  $$$$$$\\  $$$$$$$\\
      // \\_$$  _|  $$  __$$\\ $$ |$$  __$$\\ $$  __$$ |$$ | $$ | $$ |$$  __$$\\ $$  __$$\\
      //   $$ |    $$ |  $$ |$$ |$$ |  \\__|$$ /  $$ |$$ | $$ | $$ |$$$$$$$$ |$$ |  $$ |
      //   $$ |$$\\ $$ |  $$ |$$ |$$ |      $$ |  $$ |$$ | $$ | $$ |$$   ____|$$ |  $$ |
      //   \\$$$$  |$$ |  $$ |$$ |$$ |      \\$$$$$$$ |\\$$$$$\\$$$$  |\\$$$$$$$\\ $$$$$$$  |
      //    \\____/ \\__|  \\__|\\__|\\__|       \\_______| \\_____\\____/  \\_______|\\_______/
      import "./extension/interface/IContractFactory.sol";
      import "@openzeppelin/contracts/metatx/ERC2771Context.sol";
      import "@openzeppelin/contracts/utils/Multicall.sol";
      import "@openzeppelin/contracts/proxy/Clones.sol";
      contract TWCloneFactory is Multicall, ERC2771Context, IContractFactory {
          /// @dev Emitted when a proxy is deployed.
          event ProxyDeployed(address indexed implementation, address proxy, address indexed deployer);
          constructor(address _trustedForwarder) ERC2771Context(_trustedForwarder) {}
          /// @dev Deploys a proxy that points to the given implementation.
          function deployProxyByImplementation(
              address _implementation,
              bytes memory _data,
              bytes32 _salt
          ) public override returns (address deployedProxy) {
              bytes32 salthash = keccak256(abi.encodePacked(_msgSender(), _salt));
              deployedProxy = Clones.cloneDeterministic(_implementation, salthash);
              emit ProxyDeployed(_implementation, deployedProxy, _msgSender());
              if (_data.length > 0) {
                  // slither-disable-next-line unused-return
                  Address.functionCall(deployedProxy, _data);
              }
          }
          function _msgSender() internal view virtual override returns (address sender) {
              return ERC2771Context._msgSender();
          }
          function _msgData() internal view virtual override returns (bytes calldata) {
              return ERC2771Context._msgData();
          }
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      interface IContractFactory {
          /**
           *  @notice Deploys a proxy that points to that points to the given implementation.
           *
           *  @param implementation           Address of the implementation to point to.
           *
           *  @param data                     Additional data to pass to the proxy constructor or any other data useful during deployement.
           *  @param salt                     Salt to use for the deterministic address generation.
           */
          function deployProxyByImplementation(
              address implementation,
              bytes memory data,
              bytes32 salt
          ) external returns (address);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol)
      pragma solidity ^0.8.9;
      import "../utils/Context.sol";
      /**
       * @dev Context variant with ERC2771 support.
       */
      abstract contract ERC2771Context is Context {
          /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
          address private immutable _trustedForwarder;
          /// @custom:oz-upgrades-unsafe-allow constructor
          constructor(address trustedForwarder) {
              _trustedForwarder = trustedForwarder;
          }
          function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
              return forwarder == _trustedForwarder;
          }
          function _msgSender() internal view virtual override returns (address sender) {
              if (isTrustedForwarder(msg.sender)) {
                  // The assembly code is more direct than the Solidity version using `abi.decode`.
                  /// @solidity memory-safe-assembly
                  assembly {
                      sender := shr(96, calldataload(sub(calldatasize(), 20)))
                  }
              } else {
                  return super._msgSender();
              }
          }
          function _msgData() internal view virtual override returns (bytes calldata) {
              if (isTrustedForwarder(msg.sender)) {
                  return msg.data[:msg.data.length - 20];
              } else {
                  return super._msgData();
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (proxy/Clones.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
       * deploying minimal proxy contracts, also known as "clones".
       *
       * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
       * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
       *
       * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
       * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
       * deterministic method.
       *
       * _Available since v3.4._
       */
      library Clones {
          /**
           * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
           *
           * This function uses the create opcode, which should never revert.
           */
          function clone(address implementation) internal returns (address instance) {
              /// @solidity memory-safe-assembly
              assembly {
                  let ptr := mload(0x40)
                  mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                  mstore(add(ptr, 0x14), shl(0x60, implementation))
                  mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
                  instance := create(0, ptr, 0x37)
              }
              require(instance != address(0), "ERC1167: create failed");
          }
          /**
           * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
           *
           * This function uses the create2 opcode and a `salt` to deterministically deploy
           * the clone. Using the same `implementation` and `salt` multiple time will revert, since
           * the clones cannot be deployed twice at the same address.
           */
          function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
              /// @solidity memory-safe-assembly
              assembly {
                  let ptr := mload(0x40)
                  mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                  mstore(add(ptr, 0x14), shl(0x60, implementation))
                  mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
                  instance := create2(0, ptr, 0x37, salt)
              }
              require(instance != address(0), "ERC1167: create2 failed");
          }
          /**
           * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
           */
          function predictDeterministicAddress(
              address implementation,
              bytes32 salt,
              address deployer
          ) internal pure returns (address predicted) {
              /// @solidity memory-safe-assembly
              assembly {
                  let ptr := mload(0x40)
                  mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                  mstore(add(ptr, 0x14), shl(0x60, implementation))
                  mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
                  mstore(add(ptr, 0x38), shl(0x60, deployer))
                  mstore(add(ptr, 0x4c), salt)
                  mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
                  predicted := keccak256(add(ptr, 0x37), 0x55)
              }
          }
          /**
           * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
           */
          function predictDeterministicAddress(address implementation, bytes32 salt)
              internal
              view
              returns (address predicted)
          {
              return predictDeterministicAddress(implementation, salt, address(this));
          }
      }
      // 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 Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           *
           * [IMPORTANT]
           * ====
           * You shouldn't rely on `isContract` to protect against flash loan attacks!
           *
           * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
           * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
           * constructor.
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize/address.code.length, which returns 0
              // for contracts in construction, since the code is only stored at the end
              // of the constructor execution.
              return account.code.length > 0;
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
              (bool success, ) = recipient.call{value: amount}("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain `call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason, it is bubbled up by this
           * function (like regular Solidity function calls).
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           *
           * _Available since v3.1._
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionCall(target, data, "Address: low-level call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
           * `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
          }
          /**
           * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
           * with `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value,
              string memory errorMessage
          ) internal returns (bytes memory) {
              require(address(this).balance >= value, "Address: insufficient balance for call");
              require(isContract(target), "Address: call to non-contract");
              (bool success, bytes memory returndata) = target.call{value: value}(data);
              return verifyCallResult(success, returndata, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              return functionStaticCall(target, data, "Address: low-level static call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal view returns (bytes memory) {
              require(isContract(target), "Address: static call to non-contract");
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResult(success, returndata, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a delegate call.
           *
           * _Available since v3.4._
           */
          function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionDelegateCall(target, data, "Address: low-level delegate call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a delegate call.
           *
           * _Available since v3.4._
           */
          function functionDelegateCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal returns (bytes memory) {
              require(isContract(target), "Address: delegate call to non-contract");
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResult(success, returndata, errorMessage);
          }
          /**
           * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
           * revert reason using the provided one.
           *
           * _Available since v4.3._
           */
          function verifyCallResult(
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal pure returns (bytes memory) {
              if (success) {
                  return returndata;
              } else {
                  // Look for revert reason and bubble it up if present
                  if (returndata.length > 0) {
                      // The easiest way to bubble the revert reason is using memory via assembly
                      /// @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;
      /**
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol)
      pragma solidity ^0.8.0;
      import "./Address.sol";
      /**
       * @dev Provides a function to batch together multiple calls in a single external call.
       *
       * _Available since v4.1._
       */
      abstract contract Multicall {
          /**
           * @dev Receives and executes a batch of function calls on this contract.
           */
          function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
              results = new bytes[](data.length);
              for (uint256 i = 0; i < data.length; i++) {
                  results[i] = Address.functionDelegateCall(address(this), data[i]);
              }
              return results;
          }
      }
      

      File 2 of 3: AirdropERC721
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.11;
      /// @author thirdweb
      //   $$\\     $$\\       $$\\                 $$\\                         $$\\
      //   $$ |    $$ |      \\__|                $$ |                        $$ |
      // $$$$$$\\   $$$$$$$\\  $$\\  $$$$$$\\   $$$$$$$ |$$\\  $$\\  $$\\  $$$$$$\\  $$$$$$$\\
      // \\_$$  _|  $$  __$$\\ $$ |$$  __$$\\ $$  __$$ |$$ | $$ | $$ |$$  __$$\\ $$  __$$\\
      //   $$ |    $$ |  $$ |$$ |$$ |  \\__|$$ /  $$ |$$ | $$ | $$ |$$$$$$$$ |$$ |  $$ |
      //   $$ |$$\\ $$ |  $$ |$$ |$$ |      $$ |  $$ |$$ | $$ | $$ |$$   ____|$$ |  $$ |
      //   \\$$$$  |$$ |  $$ |$$ |$$ |      \\$$$$$$$ |\\$$$$$\\$$$$  |\\$$$$$$$\\ $$$$$$$  |
      //    \\____/ \\__|  \\__|\\__|\\__|       \\_______| \\_____\\____/  \\_______|\\_______/
      //  ==========  External imports    ==========
      import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
      import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
      import "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
      //  ==========  Internal imports    ==========
      import "../interfaces/airdrop/IAirdropERC721.sol";
      import "../openzeppelin-presets/metatx/ERC2771ContextUpgradeable.sol";
      //  ==========  Features    ==========
      import "../extension/PermissionsEnumerable.sol";
      import "../extension/ContractMetadata.sol";
      contract AirdropERC721 is
          Initializable,
          ContractMetadata,
          PermissionsEnumerable,
          ReentrancyGuardUpgradeable,
          ERC2771ContextUpgradeable,
          MulticallUpgradeable,
          IAirdropERC721
      {
          /*///////////////////////////////////////////////////////////////
                                  State variables
          //////////////////////////////////////////////////////////////*/
          bytes32 private constant MODULE_TYPE = bytes32("AirdropERC721");
          uint256 private constant VERSION = 2;
          /*///////////////////////////////////////////////////////////////
                          Constructor + initializer logic
          //////////////////////////////////////////////////////////////*/
          constructor() initializer {}
          /// @dev Initiliazes the contract, like a constructor.
          function initialize(
              address _defaultAdmin,
              string memory _contractURI,
              address[] memory _trustedForwarders
          ) external initializer {
              __ERC2771Context_init_unchained(_trustedForwarders);
              _setupContractURI(_contractURI);
              _setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
              __ReentrancyGuard_init();
          }
          /*///////////////////////////////////////////////////////////////
                              Generic contract logic
          //////////////////////////////////////////////////////////////*/
          /// @dev Returns the type of the contract.
          function contractType() external pure returns (bytes32) {
              return MODULE_TYPE;
          }
          /// @dev Returns the version of the contract.
          function contractVersion() external pure returns (uint8) {
              return uint8(VERSION);
          }
          /*///////////////////////////////////////////////////////////////
                                  Airdrop logic
          //////////////////////////////////////////////////////////////*/
          /**
           *  @notice          Lets contract-owner send ERC721 tokens to a list of addresses.
           *  @dev             The token-owner should approve target tokens to Airdrop contract,
           *                   which acts as operator for the tokens.
           *
           *  @param _tokenAddress    The contract address of the tokens to transfer.
           *  @param _tokenOwner      The owner of the the tokens to transfer.
           *  @param _contents        List containing recipient, tokenId to airdrop.
           */
          function airdrop(
              address _tokenAddress,
              address _tokenOwner,
              AirdropContent[] calldata _contents
          ) external nonReentrant {
              require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Not authorized.");
              uint256 len = _contents.length;
              for (uint256 i = 0; i < len; ) {
                  try
                      IERC721(_tokenAddress).safeTransferFrom(_tokenOwner, _contents[i].recipient, _contents[i].tokenId)
                  {} catch {
                      // revert if failure is due to unapproved tokens
                      require(
                          (IERC721(_tokenAddress).ownerOf(_contents[i].tokenId) == _tokenOwner &&
                              address(this) == IERC721(_tokenAddress).getApproved(_contents[i].tokenId)) ||
                              IERC721(_tokenAddress).isApprovedForAll(_tokenOwner, address(this)),
                          "Not owner or approved"
                      );
                      emit AirdropFailed(_tokenAddress, _tokenOwner, _contents[i].recipient, _contents[i].tokenId);
                  }
                  unchecked {
                      i += 1;
                  }
              }
          }
          /*///////////////////////////////////////////////////////////////
                              Miscellaneous
          //////////////////////////////////////////////////////////////*/
          /// @dev Checks whether contract metadata can be set in the given execution context.
          function _canSetContractURI() internal view override returns (bool) {
              return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
          }
          /// @dev See ERC2771
          function _msgSender() internal view virtual override returns (address sender) {
              return ERC2771ContextUpgradeable._msgSender();
          }
          /// @dev See ERC2771
          function _msgData() internal view virtual override returns (bytes calldata) {
              return ERC2771ContextUpgradeable._msgData();
          }
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      import "./interface/IContractMetadata.sol";
      /**
       *  @title   Contract Metadata
       *  @notice  Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
       *           for you contract.
       *           Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
       */
      abstract contract ContractMetadata is IContractMetadata {
          /// @notice Returns the contract metadata URI.
          string public override contractURI;
          /**
           *  @notice         Lets a contract admin set the URI for contract-level metadata.
           *  @dev            Caller should be authorized to setup contractURI, e.g. contract admin.
           *                  See {_canSetContractURI}.
           *                  Emits {ContractURIUpdated Event}.
           *
           *  @param _uri     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           */
          function setContractURI(string memory _uri) external override {
              if (!_canSetContractURI()) {
                  revert("Not authorized");
              }
              _setupContractURI(_uri);
          }
          /// @dev Lets a contract admin set the URI for contract-level metadata.
          function _setupContractURI(string memory _uri) internal {
              string memory prevURI = contractURI;
              contractURI = _uri;
              emit ContractURIUpdated(prevURI, _uri);
          }
          /// @dev Returns whether contract metadata can be set in the given execution context.
          function _canSetContractURI() internal view virtual returns (bool);
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      import "./interface/IPermissions.sol";
      import "../lib/TWStrings.sol";
      /**
       *  @title   Permissions
       *  @dev     This contracts provides extending-contracts with role-based access control mechanisms
       */
      contract Permissions is IPermissions {
          /// @dev Map from keccak256 hash of a role => a map from address => whether address has role.
          mapping(bytes32 => mapping(address => bool)) private _hasRole;
          /// @dev Map from keccak256 hash of a role to role admin. See {getRoleAdmin}.
          mapping(bytes32 => bytes32) private _getRoleAdmin;
          /// @dev Default admin role for all roles. Only accounts with this role can grant/revoke other roles.
          bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
          /// @dev Modifier that checks if an account has the specified role; reverts otherwise.
          modifier onlyRole(bytes32 role) {
              _checkRole(role, msg.sender);
              _;
          }
          /**
           *  @notice         Checks whether an account has a particular role.
           *  @dev            Returns `true` if `account` has been granted `role`.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param account  Address of the account for which the role is being checked.
           */
          function hasRole(bytes32 role, address account) public view override returns (bool) {
              return _hasRole[role][account];
          }
          /**
           *  @notice         Checks whether an account has a particular role;
           *                  role restrictions can be swtiched on and off.
           *
           *  @dev            Returns `true` if `account` has been granted `role`.
           *                  Role restrictions can be swtiched on and off:
           *                      - If address(0) has ROLE, then the ROLE restrictions
           *                        don't apply.
           *                      - If address(0) does not have ROLE, then the ROLE
           *                        restrictions will apply.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param account  Address of the account for which the role is being checked.
           */
          function hasRoleWithSwitch(bytes32 role, address account) public view returns (bool) {
              if (!_hasRole[role][address(0)]) {
                  return _hasRole[role][account];
              }
              return true;
          }
          /**
           *  @notice         Returns the admin role that controls the specified role.
           *  @dev            See {grantRole} and {revokeRole}.
           *                  To change a role's admin, use {_setRoleAdmin}.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           */
          function getRoleAdmin(bytes32 role) external view override returns (bytes32) {
              return _getRoleAdmin[role];
          }
          /**
           *  @notice         Grants a role to an account, if not previously granted.
           *  @dev            Caller must have admin role for the `role`.
           *                  Emits {RoleGranted Event}.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param account  Address of the account to which the role is being granted.
           */
          function grantRole(bytes32 role, address account) public virtual override {
              _checkRole(_getRoleAdmin[role], msg.sender);
              if (_hasRole[role][account]) {
                  revert("Can only grant to non holders");
              }
              _setupRole(role, account);
          }
          /**
           *  @notice         Revokes role from an account.
           *  @dev            Caller must have admin role for the `role`.
           *                  Emits {RoleRevoked Event}.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param account  Address of the account from which the role is being revoked.
           */
          function revokeRole(bytes32 role, address account) public virtual override {
              _checkRole(_getRoleAdmin[role], msg.sender);
              _revokeRole(role, account);
          }
          /**
           *  @notice         Revokes role from the account.
           *  @dev            Caller must have the `role`, with caller being the same as `account`.
           *                  Emits {RoleRevoked Event}.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param account  Address of the account from which the role is being revoked.
           */
          function renounceRole(bytes32 role, address account) public virtual override {
              if (msg.sender != account) {
                  revert("Can only renounce for self");
              }
              _revokeRole(role, account);
          }
          /// @dev Sets `adminRole` as `role`'s admin role.
          function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
              bytes32 previousAdminRole = _getRoleAdmin[role];
              _getRoleAdmin[role] = adminRole;
              emit RoleAdminChanged(role, previousAdminRole, adminRole);
          }
          /// @dev Sets up `role` for `account`
          function _setupRole(bytes32 role, address account) internal virtual {
              _hasRole[role][account] = true;
              emit RoleGranted(role, account, msg.sender);
          }
          /// @dev Revokes `role` from `account`
          function _revokeRole(bytes32 role, address account) internal virtual {
              _checkRole(role, account);
              delete _hasRole[role][account];
              emit RoleRevoked(role, account, msg.sender);
          }
          /// @dev Checks `role` for `account`. Reverts with a message including the required role.
          function _checkRole(bytes32 role, address account) internal view virtual {
              if (!_hasRole[role][account]) {
                  revert(
                      string(
                          abi.encodePacked(
                              "Permissions: account ",
                              TWStrings.toHexString(uint160(account), 20),
                              " is missing role ",
                              TWStrings.toHexString(uint256(role), 32)
                          )
                      )
                  );
              }
          }
          /// @dev Checks `role` for `account`. Reverts with a message including the required role.
          function _checkRoleWithSwitch(bytes32 role, address account) internal view virtual {
              if (!hasRoleWithSwitch(role, account)) {
                  revert(
                      string(
                          abi.encodePacked(
                              "Permissions: account ",
                              TWStrings.toHexString(uint160(account), 20),
                              " is missing role ",
                              TWStrings.toHexString(uint256(role), 32)
                          )
                      )
                  );
              }
          }
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      import "./interface/IPermissionsEnumerable.sol";
      import "./Permissions.sol";
      /**
       *  @title   PermissionsEnumerable
       *  @dev     This contracts provides extending-contracts with role-based access control mechanisms.
       *           Also provides interfaces to view all members with a given role, and total count of members.
       */
      contract PermissionsEnumerable is IPermissionsEnumerable, Permissions {
          /**
           *  @notice A data structure to store data of members for a given role.
           *
           *  @param index    Current index in the list of accounts that have a role.
           *  @param members  map from index => address of account that has a role
           *  @param indexOf  map from address => index which the account has.
           */
          struct RoleMembers {
              uint256 index;
              mapping(uint256 => address) members;
              mapping(address => uint256) indexOf;
          }
          /// @dev map from keccak256 hash of a role to its members' data. See {RoleMembers}.
          mapping(bytes32 => RoleMembers) private roleMembers;
          /**
           *  @notice         Returns the role-member from a list of members for a role,
           *                  at a given index.
           *  @dev            Returns `member` who has `role`, at `index` of role-members list.
           *                  See struct {RoleMembers}, and mapping {roleMembers}
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param index    Index in list of current members for the role.
           *
           *  @return member  Address of account that has `role`
           */
          function getRoleMember(bytes32 role, uint256 index) external view override returns (address member) {
              uint256 currentIndex = roleMembers[role].index;
              uint256 check;
              for (uint256 i = 0; i < currentIndex; i += 1) {
                  if (roleMembers[role].members[i] != address(0)) {
                      if (check == index) {
                          member = roleMembers[role].members[i];
                          return member;
                      }
                      check += 1;
                  } else if (hasRole(role, address(0)) && i == roleMembers[role].indexOf[address(0)]) {
                      check += 1;
                  }
              }
          }
          /**
           *  @notice         Returns total number of accounts that have a role.
           *  @dev            Returns `count` of accounts that have `role`.
           *                  See struct {RoleMembers}, and mapping {roleMembers}
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *
           *  @return count   Total number of accounts that have `role`
           */
          function getRoleMemberCount(bytes32 role) external view override returns (uint256 count) {
              uint256 currentIndex = roleMembers[role].index;
              for (uint256 i = 0; i < currentIndex; i += 1) {
                  if (roleMembers[role].members[i] != address(0)) {
                      count += 1;
                  }
              }
              if (hasRole(role, address(0))) {
                  count += 1;
              }
          }
          /// @dev Revokes `role` from `account`, and removes `account` from {roleMembers}
          ///      See {_removeMember}
          function _revokeRole(bytes32 role, address account) internal override {
              super._revokeRole(role, account);
              _removeMember(role, account);
          }
          /// @dev Grants `role` to `account`, and adds `account` to {roleMembers}
          ///      See {_addMember}
          function _setupRole(bytes32 role, address account) internal override {
              super._setupRole(role, account);
              _addMember(role, account);
          }
          /// @dev adds `account` to {roleMembers}, for `role`
          function _addMember(bytes32 role, address account) internal {
              uint256 idx = roleMembers[role].index;
              roleMembers[role].index += 1;
              roleMembers[role].members[idx] = account;
              roleMembers[role].indexOf[account] = idx;
          }
          /// @dev removes `account` from {roleMembers}, for `role`
          function _removeMember(bytes32 role, address account) internal {
              uint256 idx = roleMembers[role].indexOf[account];
              delete roleMembers[role].members[idx];
              delete roleMembers[role].indexOf[account];
          }
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      /**
       *  Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
       *  for you contract.
       *
       *  Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
       */
      interface IContractMetadata {
          /// @dev Returns the metadata URI of the contract.
          function contractURI() external view returns (string memory);
          /**
           *  @dev Sets contract URI for the storefront-level metadata of the contract.
           *       Only module admin can call this function.
           */
          function setContractURI(string calldata _uri) external;
          /// @dev Emitted when the contract URI is updated.
          event ContractURIUpdated(string prevURI, string newURI);
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      /**
       * @dev External interface of AccessControl declared to support ERC165 detection.
       */
      interface IPermissions {
          /**
           * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
           *
           * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
           * {RoleAdminChanged} not being emitted signaling this.
           *
           * _Available since v3.1._
           */
          event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
          /**
           * @dev Emitted when `account` is granted `role`.
           *
           * `sender` is the account that originated the contract call, an admin role
           * bearer except when using {AccessControl-_setupRole}.
           */
          event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
          /**
           * @dev Emitted when `account` is revoked `role`.
           *
           * `sender` is the account that originated the contract call:
           *   - if using `revokeRole`, it is the admin role bearer
           *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
           */
          event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
          /**
           * @dev Returns `true` if `account` has been granted `role`.
           */
          function hasRole(bytes32 role, address account) external view returns (bool);
          /**
           * @dev Returns the admin role that controls `role`. See {grantRole} and
           * {revokeRole}.
           *
           * To change a role's admin, use {AccessControl-_setRoleAdmin}.
           */
          function getRoleAdmin(bytes32 role) external view returns (bytes32);
          /**
           * @dev Grants `role` to `account`.
           *
           * If `account` had not been already granted `role`, emits a {RoleGranted}
           * event.
           *
           * Requirements:
           *
           * - the caller must have ``role``'s admin role.
           */
          function grantRole(bytes32 role, address account) external;
          /**
           * @dev Revokes `role` from `account`.
           *
           * If `account` had been granted `role`, emits a {RoleRevoked} event.
           *
           * Requirements:
           *
           * - the caller must have ``role``'s admin role.
           */
          function revokeRole(bytes32 role, address account) external;
          /**
           * @dev Revokes `role` from the calling account.
           *
           * Roles are often managed via {grantRole} and {revokeRole}: this function's
           * purpose is to provide a mechanism for accounts to lose their privileges
           * if they are compromised (such as when a trusted device is misplaced).
           *
           * If the calling account had been granted `role`, emits a {RoleRevoked}
           * event.
           *
           * Requirements:
           *
           * - the caller must be `account`.
           */
          function renounceRole(bytes32 role, address account) external;
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      import "./IPermissions.sol";
      /**
       * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
       */
      interface IPermissionsEnumerable is IPermissions {
          /**
           * @dev Returns one of the accounts that have `role`. `index` must be a
           * value between 0 and {getRoleMemberCount}, non-inclusive.
           *
           * Role bearers are not sorted in any particular way, and their ordering may
           * change at any point.
           *
           * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
           * you perform all queries on the same block. See the following
           * [forum post](https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296)
           * for more information.
           */
          function getRoleMember(bytes32 role, uint256 index) external view returns (address);
          /**
           * @dev Returns the number of accounts that have `role`. Can be used
           * together with {getRoleMember} to enumerate all bearers of a role.
           */
          function getRoleMemberCount(bytes32 role) external view returns (uint256);
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.11;
      /**
       *  Thirdweb's `Airdrop` contracts provide a lightweight and easy to use mechanism
       *  to drop tokens.
       *
       *  `AirdropERC721` contract is an airdrop contract for ERC721 tokens. It follows a
       *  push mechanism for transfer of tokens to intended recipients.
       */
      interface IAirdropERC721 {
          /// @notice Emitted when an airdrop fails for a recipient address.
          event AirdropFailed(
              address indexed tokenAddress,
              address indexed tokenOwner,
              address indexed recipient,
              uint256 tokenId
          );
          /**
           *  @notice Details of amount and recipient for airdropped token.
           *
           *  @param recipient The recipient of the tokens.
           *  @param tokenId ID of the ERC721 token being airdropped.
           */
          struct AirdropContent {
              address recipient;
              uint256 tokenId;
          }
          /**
           *  @notice          Lets contract-owner send ERC721 tokens to a list of addresses.
           *  @dev             The token-owner should approve target tokens to Airdrop contract,
           *                   which acts as operator for the tokens.
           *
           *  @param tokenAddress    The contract address of the tokens to transfer.
           *  @param tokenOwner      The owner of the the tokens to transfer.
           *  @param contents        List containing recipient, tokenId to airdrop.
           */
          function airdrop(
              address tokenAddress,
              address tokenOwner,
              AirdropContent[] calldata contents
          ) external;
      }
      // SPDX-License-Identifier: Apache 2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      /**
       * @dev String operations.
       */
      library TWStrings {
          bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
          /**
           * @dev Converts a `uint256` to its ASCII `string` decimal representation.
           */
          function toString(uint256 value) internal pure returns (string memory) {
              // Inspired by OraclizeAPI's implementation - MIT licence
              // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
              if (value == 0) {
                  return "0";
              }
              uint256 temp = value;
              uint256 digits;
              while (temp != 0) {
                  digits++;
                  temp /= 10;
              }
              bytes memory buffer = new bytes(digits);
              while (value != 0) {
                  digits -= 1;
                  buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                  value /= 10;
              }
              return string(buffer);
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
           */
          function toHexString(uint256 value) internal pure returns (string memory) {
              if (value == 0) {
                  return "0x00";
              }
              uint256 temp = value;
              uint256 length = 0;
              while (temp != 0) {
                  length++;
                  temp >>= 8;
              }
              return toHexString(value, length);
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
           */
          function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
              bytes memory buffer = new bytes(2 * length + 2);
              buffer[0] = "0";
              buffer[1] = "x";
              for (uint256 i = 2 * length + 1; i > 1; --i) {
                  buffer[i] = _HEX_SYMBOLS[value & 0xf];
                  value >>= 4;
              }
              require(value == 0, "Strings: hex length insufficient");
              return string(buffer);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.0 (metatx/ERC2771Context.sol)
      pragma solidity ^0.8.11;
      import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
      import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
      /**
       * @dev Context variant with ERC2771 support.
       */
      abstract contract ERC2771ContextUpgradeable is Initializable, ContextUpgradeable {
          mapping(address => bool) private _trustedForwarder;
          function __ERC2771Context_init(address[] memory trustedForwarder) internal onlyInitializing {
              __Context_init_unchained();
              __ERC2771Context_init_unchained(trustedForwarder);
          }
          function __ERC2771Context_init_unchained(address[] memory trustedForwarder) internal onlyInitializing {
              for (uint256 i = 0; i < trustedForwarder.length; i++) {
                  _trustedForwarder[trustedForwarder[i]] = true;
              }
          }
          function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
              return _trustedForwarder[forwarder];
          }
          function _msgSender() internal view virtual override returns (address sender) {
              if (isTrustedForwarder(msg.sender)) {
                  // The assembly code is more direct than the Solidity version using `abi.decode`.
                  assembly {
                      sender := shr(96, calldataload(sub(calldatasize(), 20)))
                  }
              } else {
                  return super._msgSender();
              }
          }
          function _msgData() internal view virtual override returns (bytes calldata) {
              if (isTrustedForwarder(msg.sender)) {
                  return msg.data[:msg.data.length - 20];
              } else {
                  return super._msgData();
              }
          }
          uint256[49] 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 v4.4.1 (security/ReentrancyGuard.sol)
      pragma solidity ^0.8.0;
      import "../proxy/utils/Initializable.sol";
      /**
       * @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].
       */
      abstract contract ReentrancyGuardUpgradeable is Initializable {
          // 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 constant _NOT_ENTERED = 1;
          uint256 private constant _ENTERED = 2;
          uint256 private _status;
          function __ReentrancyGuard_init() internal onlyInitializing {
              __ReentrancyGuard_init_unchained();
          }
          function __ReentrancyGuard_init_unchained() internal onlyInitializing {
              _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 making 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;
          }
          /**
           * @dev This empty reserved space is put in place to allow future versions to add new
           * variables without shifting down storage in the inheritance chain.
           * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
           */
          uint256[49] private __gap;
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
      pragma solidity ^0.8.1;
      /**
       * @dev Collection of functions related to the address type
       */
      library AddressUpgradeable {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           *
           * [IMPORTANT]
           * ====
           * You shouldn't rely on `isContract` to protect against flash loan attacks!
           *
           * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
           * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
           * constructor.
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize/address.code.length, which returns 0
              // for contracts in construction, since the code is only stored at the end
              // of the constructor execution.
              return account.code.length > 0;
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
              (bool success, ) = recipient.call{value: amount}("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain `call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason, it is bubbled up by this
           * function (like regular Solidity function calls).
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           *
           * _Available since v3.1._
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionCall(target, data, "Address: low-level call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
           * `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
          }
          /**
           * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
           * with `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value,
              string memory errorMessage
          ) internal returns (bytes memory) {
              require(address(this).balance >= value, "Address: insufficient balance for call");
              require(isContract(target), "Address: call to non-contract");
              (bool success, bytes memory returndata) = target.call{value: value}(data);
              return verifyCallResult(success, returndata, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              return functionStaticCall(target, data, "Address: low-level static call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal view returns (bytes memory) {
              require(isContract(target), "Address: static call to non-contract");
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResult(success, returndata, errorMessage);
          }
          /**
           * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
           * revert reason using the provided one.
           *
           * _Available since v4.3._
           */
          function verifyCallResult(
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal pure returns (bytes memory) {
              if (success) {
                  return returndata;
              } else {
                  // Look for revert reason and bubble it up if present
                  if (returndata.length > 0) {
                      // The easiest way to bubble the revert reason is using memory via assembly
                      /// @solidity memory-safe-assembly
                      assembly {
                          let returndata_size := mload(returndata)
                          revert(add(32, returndata), returndata_size)
                      }
                  } else {
                      revert(errorMessage);
                  }
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
      pragma solidity ^0.8.0;
      import "../proxy/utils/Initializable.sol";
      /**
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract ContextUpgradeable is Initializable {
          function __Context_init() internal onlyInitializing {
          }
          function __Context_init_unchained() internal onlyInitializing {
          }
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
          /**
           * @dev This empty reserved space is put in place to allow future versions to add new
           * variables without shifting down storage in the inheritance chain.
           * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
           */
          uint256[50] private __gap;
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol)
      pragma solidity ^0.8.0;
      import "./AddressUpgradeable.sol";
      import "../proxy/utils/Initializable.sol";
      /**
       * @dev Provides a function to batch together multiple calls in a single external call.
       *
       * _Available since v4.1._
       */
      abstract contract MulticallUpgradeable is Initializable {
          function __Multicall_init() internal onlyInitializing {
          }
          function __Multicall_init_unchained() internal onlyInitializing {
          }
          /**
           * @dev Receives and executes a batch of function calls on this contract.
           */
          function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
              results = new bytes[](data.length);
              for (uint256 i = 0; i < data.length; i++) {
                  results[i] = _functionDelegateCall(address(this), data[i]);
              }
              return results;
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a delegate call.
           *
           * _Available since v3.4._
           */
          function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
              require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");
              // solhint-disable-next-line avoid-low-level-calls
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
          }
          /**
           * @dev This empty reserved space is put in place to allow future versions to add new
           * variables without shifting down storage in the inheritance chain.
           * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
           */
          uint256[50] private __gap;
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)
      pragma solidity ^0.8.0;
      import "../../utils/introspection/IERC165.sol";
      /**
       * @dev Required interface of an ERC721 compliant contract.
       */
      interface IERC721 is IERC165 {
          /**
           * @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`.
           *
           * Requirements:
           *
           * - `from` cannot be the zero address.
           * - `to` cannot be the zero address.
           * - `tokenId` token must exist and be owned by `from`.
           * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
           * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
           *
           * Emits a {Transfer} event.
           */
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId,
              bytes calldata data
          ) external;
          /**
           * @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 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
          ) external;
          /**
           * @dev Transfers `tokenId` token 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;
          /**
           * @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;
          /**
           * @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);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev Interface of the ERC165 standard, as defined in the
       * https://eips.ethereum.org/EIPS/eip-165[EIP].
       *
       * Implementers can declare support of contract interfaces, which can then be
       * queried by others ({ERC165Checker}).
       *
       * For an implementation, see {ERC165}.
       */
      interface IERC165 {
          /**
           * @dev Returns true if this contract implements the interface defined by
           * `interfaceId`. See the corresponding
           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
           * to learn more about how these ids are created.
           *
           * This function call must use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
      }
      

      File 3 of 3: AirdropERC721
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.11;
      /// @author thirdweb
      //   $$\\     $$\\       $$\\                 $$\\                         $$\\
      //   $$ |    $$ |      \\__|                $$ |                        $$ |
      // $$$$$$\\   $$$$$$$\\  $$\\  $$$$$$\\   $$$$$$$ |$$\\  $$\\  $$\\  $$$$$$\\  $$$$$$$\\
      // \\_$$  _|  $$  __$$\\ $$ |$$  __$$\\ $$  __$$ |$$ | $$ | $$ |$$  __$$\\ $$  __$$\\
      //   $$ |    $$ |  $$ |$$ |$$ |  \\__|$$ /  $$ |$$ | $$ | $$ |$$$$$$$$ |$$ |  $$ |
      //   $$ |$$\\ $$ |  $$ |$$ |$$ |      $$ |  $$ |$$ | $$ | $$ |$$   ____|$$ |  $$ |
      //   \\$$$$  |$$ |  $$ |$$ |$$ |      \\$$$$$$$ |\\$$$$$\\$$$$  |\\$$$$$$$\\ $$$$$$$  |
      //    \\____/ \\__|  \\__|\\__|\\__|       \\_______| \\_____\\____/  \\_______|\\_______/
      //  ==========  External imports    ==========
      import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
      import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
      import "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
      //  ==========  Internal imports    ==========
      import "../interfaces/airdrop/IAirdropERC721.sol";
      import "../openzeppelin-presets/metatx/ERC2771ContextUpgradeable.sol";
      //  ==========  Features    ==========
      import "../extension/PermissionsEnumerable.sol";
      import "../extension/ContractMetadata.sol";
      contract AirdropERC721 is
          Initializable,
          ContractMetadata,
          PermissionsEnumerable,
          ReentrancyGuardUpgradeable,
          ERC2771ContextUpgradeable,
          MulticallUpgradeable,
          IAirdropERC721
      {
          /*///////////////////////////////////////////////////////////////
                                  State variables
          //////////////////////////////////////////////////////////////*/
          bytes32 private constant MODULE_TYPE = bytes32("AirdropERC721");
          uint256 private constant VERSION = 2;
          /*///////////////////////////////////////////////////////////////
                          Constructor + initializer logic
          //////////////////////////////////////////////////////////////*/
          constructor() initializer {}
          /// @dev Initiliazes the contract, like a constructor.
          function initialize(
              address _defaultAdmin,
              string memory _contractURI,
              address[] memory _trustedForwarders
          ) external initializer {
              __ERC2771Context_init_unchained(_trustedForwarders);
              _setupContractURI(_contractURI);
              _setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
              __ReentrancyGuard_init();
          }
          /*///////////////////////////////////////////////////////////////
                              Generic contract logic
          //////////////////////////////////////////////////////////////*/
          /// @dev Returns the type of the contract.
          function contractType() external pure returns (bytes32) {
              return MODULE_TYPE;
          }
          /// @dev Returns the version of the contract.
          function contractVersion() external pure returns (uint8) {
              return uint8(VERSION);
          }
          /*///////////////////////////////////////////////////////////////
                                  Airdrop logic
          //////////////////////////////////////////////////////////////*/
          /**
           *  @notice          Lets contract-owner send ERC721 tokens to a list of addresses.
           *  @dev             The token-owner should approve target tokens to Airdrop contract,
           *                   which acts as operator for the tokens.
           *
           *  @param _tokenAddress    The contract address of the tokens to transfer.
           *  @param _tokenOwner      The owner of the the tokens to transfer.
           *  @param _contents        List containing recipient, tokenId to airdrop.
           */
          function airdrop(
              address _tokenAddress,
              address _tokenOwner,
              AirdropContent[] calldata _contents
          ) external nonReentrant {
              require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Not authorized.");
              uint256 len = _contents.length;
              for (uint256 i = 0; i < len; ) {
                  try
                      IERC721(_tokenAddress).safeTransferFrom(_tokenOwner, _contents[i].recipient, _contents[i].tokenId)
                  {} catch {
                      // revert if failure is due to unapproved tokens
                      require(
                          (IERC721(_tokenAddress).ownerOf(_contents[i].tokenId) == _tokenOwner &&
                              address(this) == IERC721(_tokenAddress).getApproved(_contents[i].tokenId)) ||
                              IERC721(_tokenAddress).isApprovedForAll(_tokenOwner, address(this)),
                          "Not owner or approved"
                      );
                      emit AirdropFailed(_tokenAddress, _tokenOwner, _contents[i].recipient, _contents[i].tokenId);
                  }
                  unchecked {
                      i += 1;
                  }
              }
          }
          /*///////////////////////////////////////////////////////////////
                              Miscellaneous
          //////////////////////////////////////////////////////////////*/
          /// @dev Checks whether contract metadata can be set in the given execution context.
          function _canSetContractURI() internal view override returns (bool) {
              return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
          }
          /// @dev See ERC2771
          function _msgSender() internal view virtual override returns (address sender) {
              return ERC2771ContextUpgradeable._msgSender();
          }
          /// @dev See ERC2771
          function _msgData() internal view virtual override returns (bytes calldata) {
              return ERC2771ContextUpgradeable._msgData();
          }
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      import "./interface/IContractMetadata.sol";
      /**
       *  @title   Contract Metadata
       *  @notice  Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
       *           for you contract.
       *           Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
       */
      abstract contract ContractMetadata is IContractMetadata {
          /// @notice Returns the contract metadata URI.
          string public override contractURI;
          /**
           *  @notice         Lets a contract admin set the URI for contract-level metadata.
           *  @dev            Caller should be authorized to setup contractURI, e.g. contract admin.
           *                  See {_canSetContractURI}.
           *                  Emits {ContractURIUpdated Event}.
           *
           *  @param _uri     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           */
          function setContractURI(string memory _uri) external override {
              if (!_canSetContractURI()) {
                  revert("Not authorized");
              }
              _setupContractURI(_uri);
          }
          /// @dev Lets a contract admin set the URI for contract-level metadata.
          function _setupContractURI(string memory _uri) internal {
              string memory prevURI = contractURI;
              contractURI = _uri;
              emit ContractURIUpdated(prevURI, _uri);
          }
          /// @dev Returns whether contract metadata can be set in the given execution context.
          function _canSetContractURI() internal view virtual returns (bool);
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      import "./interface/IPermissions.sol";
      import "../lib/TWStrings.sol";
      /**
       *  @title   Permissions
       *  @dev     This contracts provides extending-contracts with role-based access control mechanisms
       */
      contract Permissions is IPermissions {
          /// @dev Map from keccak256 hash of a role => a map from address => whether address has role.
          mapping(bytes32 => mapping(address => bool)) private _hasRole;
          /// @dev Map from keccak256 hash of a role to role admin. See {getRoleAdmin}.
          mapping(bytes32 => bytes32) private _getRoleAdmin;
          /// @dev Default admin role for all roles. Only accounts with this role can grant/revoke other roles.
          bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
          /// @dev Modifier that checks if an account has the specified role; reverts otherwise.
          modifier onlyRole(bytes32 role) {
              _checkRole(role, msg.sender);
              _;
          }
          /**
           *  @notice         Checks whether an account has a particular role.
           *  @dev            Returns `true` if `account` has been granted `role`.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param account  Address of the account for which the role is being checked.
           */
          function hasRole(bytes32 role, address account) public view override returns (bool) {
              return _hasRole[role][account];
          }
          /**
           *  @notice         Checks whether an account has a particular role;
           *                  role restrictions can be swtiched on and off.
           *
           *  @dev            Returns `true` if `account` has been granted `role`.
           *                  Role restrictions can be swtiched on and off:
           *                      - If address(0) has ROLE, then the ROLE restrictions
           *                        don't apply.
           *                      - If address(0) does not have ROLE, then the ROLE
           *                        restrictions will apply.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param account  Address of the account for which the role is being checked.
           */
          function hasRoleWithSwitch(bytes32 role, address account) public view returns (bool) {
              if (!_hasRole[role][address(0)]) {
                  return _hasRole[role][account];
              }
              return true;
          }
          /**
           *  @notice         Returns the admin role that controls the specified role.
           *  @dev            See {grantRole} and {revokeRole}.
           *                  To change a role's admin, use {_setRoleAdmin}.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           */
          function getRoleAdmin(bytes32 role) external view override returns (bytes32) {
              return _getRoleAdmin[role];
          }
          /**
           *  @notice         Grants a role to an account, if not previously granted.
           *  @dev            Caller must have admin role for the `role`.
           *                  Emits {RoleGranted Event}.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param account  Address of the account to which the role is being granted.
           */
          function grantRole(bytes32 role, address account) public virtual override {
              _checkRole(_getRoleAdmin[role], msg.sender);
              if (_hasRole[role][account]) {
                  revert("Can only grant to non holders");
              }
              _setupRole(role, account);
          }
          /**
           *  @notice         Revokes role from an account.
           *  @dev            Caller must have admin role for the `role`.
           *                  Emits {RoleRevoked Event}.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param account  Address of the account from which the role is being revoked.
           */
          function revokeRole(bytes32 role, address account) public virtual override {
              _checkRole(_getRoleAdmin[role], msg.sender);
              _revokeRole(role, account);
          }
          /**
           *  @notice         Revokes role from the account.
           *  @dev            Caller must have the `role`, with caller being the same as `account`.
           *                  Emits {RoleRevoked Event}.
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param account  Address of the account from which the role is being revoked.
           */
          function renounceRole(bytes32 role, address account) public virtual override {
              if (msg.sender != account) {
                  revert("Can only renounce for self");
              }
              _revokeRole(role, account);
          }
          /// @dev Sets `adminRole` as `role`'s admin role.
          function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
              bytes32 previousAdminRole = _getRoleAdmin[role];
              _getRoleAdmin[role] = adminRole;
              emit RoleAdminChanged(role, previousAdminRole, adminRole);
          }
          /// @dev Sets up `role` for `account`
          function _setupRole(bytes32 role, address account) internal virtual {
              _hasRole[role][account] = true;
              emit RoleGranted(role, account, msg.sender);
          }
          /// @dev Revokes `role` from `account`
          function _revokeRole(bytes32 role, address account) internal virtual {
              _checkRole(role, account);
              delete _hasRole[role][account];
              emit RoleRevoked(role, account, msg.sender);
          }
          /// @dev Checks `role` for `account`. Reverts with a message including the required role.
          function _checkRole(bytes32 role, address account) internal view virtual {
              if (!_hasRole[role][account]) {
                  revert(
                      string(
                          abi.encodePacked(
                              "Permissions: account ",
                              TWStrings.toHexString(uint160(account), 20),
                              " is missing role ",
                              TWStrings.toHexString(uint256(role), 32)
                          )
                      )
                  );
              }
          }
          /// @dev Checks `role` for `account`. Reverts with a message including the required role.
          function _checkRoleWithSwitch(bytes32 role, address account) internal view virtual {
              if (!hasRoleWithSwitch(role, account)) {
                  revert(
                      string(
                          abi.encodePacked(
                              "Permissions: account ",
                              TWStrings.toHexString(uint160(account), 20),
                              " is missing role ",
                              TWStrings.toHexString(uint256(role), 32)
                          )
                      )
                  );
              }
          }
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      import "./interface/IPermissionsEnumerable.sol";
      import "./Permissions.sol";
      /**
       *  @title   PermissionsEnumerable
       *  @dev     This contracts provides extending-contracts with role-based access control mechanisms.
       *           Also provides interfaces to view all members with a given role, and total count of members.
       */
      contract PermissionsEnumerable is IPermissionsEnumerable, Permissions {
          /**
           *  @notice A data structure to store data of members for a given role.
           *
           *  @param index    Current index in the list of accounts that have a role.
           *  @param members  map from index => address of account that has a role
           *  @param indexOf  map from address => index which the account has.
           */
          struct RoleMembers {
              uint256 index;
              mapping(uint256 => address) members;
              mapping(address => uint256) indexOf;
          }
          /// @dev map from keccak256 hash of a role to its members' data. See {RoleMembers}.
          mapping(bytes32 => RoleMembers) private roleMembers;
          /**
           *  @notice         Returns the role-member from a list of members for a role,
           *                  at a given index.
           *  @dev            Returns `member` who has `role`, at `index` of role-members list.
           *                  See struct {RoleMembers}, and mapping {roleMembers}
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *  @param index    Index in list of current members for the role.
           *
           *  @return member  Address of account that has `role`
           */
          function getRoleMember(bytes32 role, uint256 index) external view override returns (address member) {
              uint256 currentIndex = roleMembers[role].index;
              uint256 check;
              for (uint256 i = 0; i < currentIndex; i += 1) {
                  if (roleMembers[role].members[i] != address(0)) {
                      if (check == index) {
                          member = roleMembers[role].members[i];
                          return member;
                      }
                      check += 1;
                  } else if (hasRole(role, address(0)) && i == roleMembers[role].indexOf[address(0)]) {
                      check += 1;
                  }
              }
          }
          /**
           *  @notice         Returns total number of accounts that have a role.
           *  @dev            Returns `count` of accounts that have `role`.
           *                  See struct {RoleMembers}, and mapping {roleMembers}
           *
           *  @param role     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
           *
           *  @return count   Total number of accounts that have `role`
           */
          function getRoleMemberCount(bytes32 role) external view override returns (uint256 count) {
              uint256 currentIndex = roleMembers[role].index;
              for (uint256 i = 0; i < currentIndex; i += 1) {
                  if (roleMembers[role].members[i] != address(0)) {
                      count += 1;
                  }
              }
              if (hasRole(role, address(0))) {
                  count += 1;
              }
          }
          /// @dev Revokes `role` from `account`, and removes `account` from {roleMembers}
          ///      See {_removeMember}
          function _revokeRole(bytes32 role, address account) internal override {
              super._revokeRole(role, account);
              _removeMember(role, account);
          }
          /// @dev Grants `role` to `account`, and adds `account` to {roleMembers}
          ///      See {_addMember}
          function _setupRole(bytes32 role, address account) internal override {
              super._setupRole(role, account);
              _addMember(role, account);
          }
          /// @dev adds `account` to {roleMembers}, for `role`
          function _addMember(bytes32 role, address account) internal {
              uint256 idx = roleMembers[role].index;
              roleMembers[role].index += 1;
              roleMembers[role].members[idx] = account;
              roleMembers[role].indexOf[account] = idx;
          }
          /// @dev removes `account` from {roleMembers}, for `role`
          function _removeMember(bytes32 role, address account) internal {
              uint256 idx = roleMembers[role].indexOf[account];
              delete roleMembers[role].members[idx];
              delete roleMembers[role].indexOf[account];
          }
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      /**
       *  Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
       *  for you contract.
       *
       *  Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
       */
      interface IContractMetadata {
          /// @dev Returns the metadata URI of the contract.
          function contractURI() external view returns (string memory);
          /**
           *  @dev Sets contract URI for the storefront-level metadata of the contract.
           *       Only module admin can call this function.
           */
          function setContractURI(string calldata _uri) external;
          /// @dev Emitted when the contract URI is updated.
          event ContractURIUpdated(string prevURI, string newURI);
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      /**
       * @dev External interface of AccessControl declared to support ERC165 detection.
       */
      interface IPermissions {
          /**
           * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
           *
           * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
           * {RoleAdminChanged} not being emitted signaling this.
           *
           * _Available since v3.1._
           */
          event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
          /**
           * @dev Emitted when `account` is granted `role`.
           *
           * `sender` is the account that originated the contract call, an admin role
           * bearer except when using {AccessControl-_setupRole}.
           */
          event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
          /**
           * @dev Emitted when `account` is revoked `role`.
           *
           * `sender` is the account that originated the contract call:
           *   - if using `revokeRole`, it is the admin role bearer
           *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
           */
          event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
          /**
           * @dev Returns `true` if `account` has been granted `role`.
           */
          function hasRole(bytes32 role, address account) external view returns (bool);
          /**
           * @dev Returns the admin role that controls `role`. See {grantRole} and
           * {revokeRole}.
           *
           * To change a role's admin, use {AccessControl-_setRoleAdmin}.
           */
          function getRoleAdmin(bytes32 role) external view returns (bytes32);
          /**
           * @dev Grants `role` to `account`.
           *
           * If `account` had not been already granted `role`, emits a {RoleGranted}
           * event.
           *
           * Requirements:
           *
           * - the caller must have ``role``'s admin role.
           */
          function grantRole(bytes32 role, address account) external;
          /**
           * @dev Revokes `role` from `account`.
           *
           * If `account` had been granted `role`, emits a {RoleRevoked} event.
           *
           * Requirements:
           *
           * - the caller must have ``role``'s admin role.
           */
          function revokeRole(bytes32 role, address account) external;
          /**
           * @dev Revokes `role` from the calling account.
           *
           * Roles are often managed via {grantRole} and {revokeRole}: this function's
           * purpose is to provide a mechanism for accounts to lose their privileges
           * if they are compromised (such as when a trusted device is misplaced).
           *
           * If the calling account had been granted `role`, emits a {RoleRevoked}
           * event.
           *
           * Requirements:
           *
           * - the caller must be `account`.
           */
          function renounceRole(bytes32 role, address account) external;
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      import "./IPermissions.sol";
      /**
       * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
       */
      interface IPermissionsEnumerable is IPermissions {
          /**
           * @dev Returns one of the accounts that have `role`. `index` must be a
           * value between 0 and {getRoleMemberCount}, non-inclusive.
           *
           * Role bearers are not sorted in any particular way, and their ordering may
           * change at any point.
           *
           * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
           * you perform all queries on the same block. See the following
           * [forum post](https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296)
           * for more information.
           */
          function getRoleMember(bytes32 role, uint256 index) external view returns (address);
          /**
           * @dev Returns the number of accounts that have `role`. Can be used
           * together with {getRoleMember} to enumerate all bearers of a role.
           */
          function getRoleMemberCount(bytes32 role) external view returns (uint256);
      }
      // SPDX-License-Identifier: Apache-2.0
      pragma solidity ^0.8.11;
      /**
       *  Thirdweb's `Airdrop` contracts provide a lightweight and easy to use mechanism
       *  to drop tokens.
       *
       *  `AirdropERC721` contract is an airdrop contract for ERC721 tokens. It follows a
       *  push mechanism for transfer of tokens to intended recipients.
       */
      interface IAirdropERC721 {
          /// @notice Emitted when an airdrop fails for a recipient address.
          event AirdropFailed(
              address indexed tokenAddress,
              address indexed tokenOwner,
              address indexed recipient,
              uint256 tokenId
          );
          /**
           *  @notice Details of amount and recipient for airdropped token.
           *
           *  @param recipient The recipient of the tokens.
           *  @param tokenId ID of the ERC721 token being airdropped.
           */
          struct AirdropContent {
              address recipient;
              uint256 tokenId;
          }
          /**
           *  @notice          Lets contract-owner send ERC721 tokens to a list of addresses.
           *  @dev             The token-owner should approve target tokens to Airdrop contract,
           *                   which acts as operator for the tokens.
           *
           *  @param tokenAddress    The contract address of the tokens to transfer.
           *  @param tokenOwner      The owner of the the tokens to transfer.
           *  @param contents        List containing recipient, tokenId to airdrop.
           */
          function airdrop(
              address tokenAddress,
              address tokenOwner,
              AirdropContent[] calldata contents
          ) external;
      }
      // SPDX-License-Identifier: Apache 2.0
      pragma solidity ^0.8.0;
      /// @author thirdweb
      /**
       * @dev String operations.
       */
      library TWStrings {
          bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
          /**
           * @dev Converts a `uint256` to its ASCII `string` decimal representation.
           */
          function toString(uint256 value) internal pure returns (string memory) {
              // Inspired by OraclizeAPI's implementation - MIT licence
              // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
              if (value == 0) {
                  return "0";
              }
              uint256 temp = value;
              uint256 digits;
              while (temp != 0) {
                  digits++;
                  temp /= 10;
              }
              bytes memory buffer = new bytes(digits);
              while (value != 0) {
                  digits -= 1;
                  buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                  value /= 10;
              }
              return string(buffer);
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
           */
          function toHexString(uint256 value) internal pure returns (string memory) {
              if (value == 0) {
                  return "0x00";
              }
              uint256 temp = value;
              uint256 length = 0;
              while (temp != 0) {
                  length++;
                  temp >>= 8;
              }
              return toHexString(value, length);
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
           */
          function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
              bytes memory buffer = new bytes(2 * length + 2);
              buffer[0] = "0";
              buffer[1] = "x";
              for (uint256 i = 2 * length + 1; i > 1; --i) {
                  buffer[i] = _HEX_SYMBOLS[value & 0xf];
                  value >>= 4;
              }
              require(value == 0, "Strings: hex length insufficient");
              return string(buffer);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.0 (metatx/ERC2771Context.sol)
      pragma solidity ^0.8.11;
      import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
      import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
      /**
       * @dev Context variant with ERC2771 support.
       */
      abstract contract ERC2771ContextUpgradeable is Initializable, ContextUpgradeable {
          mapping(address => bool) private _trustedForwarder;
          function __ERC2771Context_init(address[] memory trustedForwarder) internal onlyInitializing {
              __Context_init_unchained();
              __ERC2771Context_init_unchained(trustedForwarder);
          }
          function __ERC2771Context_init_unchained(address[] memory trustedForwarder) internal onlyInitializing {
              for (uint256 i = 0; i < trustedForwarder.length; i++) {
                  _trustedForwarder[trustedForwarder[i]] = true;
              }
          }
          function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
              return _trustedForwarder[forwarder];
          }
          function _msgSender() internal view virtual override returns (address sender) {
              if (isTrustedForwarder(msg.sender)) {
                  // The assembly code is more direct than the Solidity version using `abi.decode`.
                  assembly {
                      sender := shr(96, calldataload(sub(calldatasize(), 20)))
                  }
              } else {
                  return super._msgSender();
              }
          }
          function _msgData() internal view virtual override returns (bytes calldata) {
              if (isTrustedForwarder(msg.sender)) {
                  return msg.data[:msg.data.length - 20];
              } else {
                  return super._msgData();
              }
          }
          uint256[49] 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 v4.4.1 (security/ReentrancyGuard.sol)
      pragma solidity ^0.8.0;
      import "../proxy/utils/Initializable.sol";
      /**
       * @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].
       */
      abstract contract ReentrancyGuardUpgradeable is Initializable {
          // 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 constant _NOT_ENTERED = 1;
          uint256 private constant _ENTERED = 2;
          uint256 private _status;
          function __ReentrancyGuard_init() internal onlyInitializing {
              __ReentrancyGuard_init_unchained();
          }
          function __ReentrancyGuard_init_unchained() internal onlyInitializing {
              _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 making 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;
          }
          /**
           * @dev This empty reserved space is put in place to allow future versions to add new
           * variables without shifting down storage in the inheritance chain.
           * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
           */
          uint256[49] private __gap;
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
      pragma solidity ^0.8.1;
      /**
       * @dev Collection of functions related to the address type
       */
      library AddressUpgradeable {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           *
           * [IMPORTANT]
           * ====
           * You shouldn't rely on `isContract` to protect against flash loan attacks!
           *
           * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
           * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
           * constructor.
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize/address.code.length, which returns 0
              // for contracts in construction, since the code is only stored at the end
              // of the constructor execution.
              return account.code.length > 0;
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
              (bool success, ) = recipient.call{value: amount}("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain `call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason, it is bubbled up by this
           * function (like regular Solidity function calls).
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           *
           * _Available since v3.1._
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionCall(target, data, "Address: low-level call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
           * `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
          }
          /**
           * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
           * with `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value,
              string memory errorMessage
          ) internal returns (bytes memory) {
              require(address(this).balance >= value, "Address: insufficient balance for call");
              require(isContract(target), "Address: call to non-contract");
              (bool success, bytes memory returndata) = target.call{value: value}(data);
              return verifyCallResult(success, returndata, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              return functionStaticCall(target, data, "Address: low-level static call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal view returns (bytes memory) {
              require(isContract(target), "Address: static call to non-contract");
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResult(success, returndata, errorMessage);
          }
          /**
           * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
           * revert reason using the provided one.
           *
           * _Available since v4.3._
           */
          function verifyCallResult(
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal pure returns (bytes memory) {
              if (success) {
                  return returndata;
              } else {
                  // Look for revert reason and bubble it up if present
                  if (returndata.length > 0) {
                      // The easiest way to bubble the revert reason is using memory via assembly
                      /// @solidity memory-safe-assembly
                      assembly {
                          let returndata_size := mload(returndata)
                          revert(add(32, returndata), returndata_size)
                      }
                  } else {
                      revert(errorMessage);
                  }
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
      pragma solidity ^0.8.0;
      import "../proxy/utils/Initializable.sol";
      /**
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract ContextUpgradeable is Initializable {
          function __Context_init() internal onlyInitializing {
          }
          function __Context_init_unchained() internal onlyInitializing {
          }
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
          /**
           * @dev This empty reserved space is put in place to allow future versions to add new
           * variables without shifting down storage in the inheritance chain.
           * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
           */
          uint256[50] private __gap;
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol)
      pragma solidity ^0.8.0;
      import "./AddressUpgradeable.sol";
      import "../proxy/utils/Initializable.sol";
      /**
       * @dev Provides a function to batch together multiple calls in a single external call.
       *
       * _Available since v4.1._
       */
      abstract contract MulticallUpgradeable is Initializable {
          function __Multicall_init() internal onlyInitializing {
          }
          function __Multicall_init_unchained() internal onlyInitializing {
          }
          /**
           * @dev Receives and executes a batch of function calls on this contract.
           */
          function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
              results = new bytes[](data.length);
              for (uint256 i = 0; i < data.length; i++) {
                  results[i] = _functionDelegateCall(address(this), data[i]);
              }
              return results;
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a delegate call.
           *
           * _Available since v3.4._
           */
          function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
              require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");
              // solhint-disable-next-line avoid-low-level-calls
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
          }
          /**
           * @dev This empty reserved space is put in place to allow future versions to add new
           * variables without shifting down storage in the inheritance chain.
           * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
           */
          uint256[50] private __gap;
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)
      pragma solidity ^0.8.0;
      import "../../utils/introspection/IERC165.sol";
      /**
       * @dev Required interface of an ERC721 compliant contract.
       */
      interface IERC721 is IERC165 {
          /**
           * @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`.
           *
           * Requirements:
           *
           * - `from` cannot be the zero address.
           * - `to` cannot be the zero address.
           * - `tokenId` token must exist and be owned by `from`.
           * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
           * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
           *
           * Emits a {Transfer} event.
           */
          function safeTransferFrom(
              address from,
              address to,
              uint256 tokenId,
              bytes calldata data
          ) external;
          /**
           * @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 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
          ) external;
          /**
           * @dev Transfers `tokenId` token 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;
          /**
           * @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;
          /**
           * @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);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev Interface of the ERC165 standard, as defined in the
       * https://eips.ethereum.org/EIPS/eip-165[EIP].
       *
       * Implementers can declare support of contract interfaces, which can then be
       * queried by others ({ERC165Checker}).
       *
       * For an implementation, see {ERC165}.
       */
      interface IERC165 {
          /**
           * @dev Returns true if this contract implements the interface defined by
           * `interfaceId`. See the corresponding
           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
           * to learn more about how these ids are created.
           *
           * This function call must use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
      }