// Contract: FractionalAsset
// Target function: function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool)
 } else {
          require(
              IERC20(token).balanceOf(msg.sender) >= totalCost,
              'Insufficient Balance'
          );
          require(
              IERC20(token).allowance(msg.sender, address(this)) >= totalCost,
              'Insufficient Allowance'
          );
          require(
              IERC20(token).transferFrom(msg.sender, mintRecipient, totalCost),
              'Error Transfer From'
          );
      }
      
      for (uint i = 0; i < num;) {
          _safeMint(to, _currentTokenID);
          unchecked { ++i; }
      }
  }

  /**
      Cumulative Dividends For A Number Of Tokens
   */
  function getCumulativeDividends(uint256 share) internal view returns (uint256) {
      return ( share * dividendsPerNFT ) / precision;
  }

  /**
      Pending Rewards For `account`
   */
  function pendingRewards(address account) public view returns (uint256) {
      if(_balances[account] == 0){ return 0; }
      if (totalRewards == 0) { return 0; }

      uint256 accountTotalDividends = getCumulativeDividends(_balances[account]);
      uint256 accountTotalExcluded = totalExcluded[account];

      if(accountTotalDividends <= accountTotalExcluded){ return 0; }

      return accountTotalDividends - accountTotalExcluded;
  }

  /**
      Total Supply of NFT
   */
  function totalSupply() external view returns (uint256) {
      return _currentTokenID;
  }

  /**
      Name Of The Collection
   */
  function name() external view override returns (string memory) {
      return _name;
  }

  /**
      Symbol (ticker) Of The Collection
   */
  function symbol() external view override returns (string memory) {
      return _symbol;
  }

  /**
      Returns The Number Of Fractions This NFT Is Split Into
   */
  function numFractions() external view override returns (uint256) {
      return nFractions;
  }

  /**
      Returns The URI To An Image Representing This Fractional Asset
   */
  function tokenURI(uint256) external view override returns (string memory) {
      return baseURI;
  }

  /**
      Returns The URI To An Image Representing This Fractional Asset
   */
  function URI() external view override returns (string memory) {
      return baseURI;
  }

  /**
   * @dev Returns the number of tokens in ``owner``'s account.
   */
  function balanceOf(address owner) external view override returns (uint256 balance) {
      return _balances[owner];
  }

  /**
   * @dev Returns the owner of the `tokenId` token.
   *
   * Requirements:
   *
   * - `tokenId` must exist.
   */
  function ownerOf(uint256 tokenId) public view returns (address owner) {
      require(
          _exists(tokenId),
          'Token Does Not Exist'
      );
      return _owners[tokenId];
  }

  /**
   * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
   * are aware of the ERC721 protocol to prevent tokens from being forever locked.
   *
   * Requirements:
   *
   * - `from` cannot be the zero address.
   * - `to` cannot be the zero address.
   * - `tokenId` token must exist and be owned by `from`.
   * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
   * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
   *
   * Emits a {Transfer} event.
   */
  function safeTransferFrom(
      address from,
      address to,
      uint256 tokenId
  ) external override {
      require(
          _isApprovedOrOwner(_msgSender(), tokenId), 
          "Transfer caller is not owner nor approved"
      );
      _safeTransfer(from, to, tokenId, new bytes(0));
  }

  /**
   * @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
  ) public override {
      require(
          _isApprovedOrOwner(_msgSender(), tokenId), 
          "Transfer caller is not owner nor approved"
      );
      _safeTransfer(from, to, tokenId, data);
  }

  /**
   * @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 override {
      require(
          _isApprovedOrOwner(_msgSender(), tokenId), 
          "Transfer caller is not owner nor approved"
      );
      _transfer(from, to, tokenId);
  }

  /**
   * @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 override {
      address owner = ownerOf(tokenId);
      require(
          to != owner, 
          "ERC721: approval to current owner"
      );
      require(
          _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
          "ERC721: approve caller is not owner nor approved for all"
      );
      _approve(to, tokenId);
  }

  /**
   * @dev Returns the account approved for `tokenId` token.
   *
   * Requirements:
   *
   * - `tokenId` must exist.
   */
  function getApproved(uint256 tokenId) public view override returns (address operator) {
      require(
          _exists(tokenId), 
          "Non Existent Token"
      );
      return _tokenApprovals[tokenId];
  }

  /**
   * @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 override {
      _setApprovalForAll(_msgSender(), operator, _approved);
  }

  /**
   * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
   *
   * See {setApprovalForAll}
   */
  function isApprovedForAll(address owner, address operator) public view override returns (bool) {
      return _operatorApprovals[owner][operator];
  }

  /**
      Claims Reward For User
   */
  function _claimRewards(address user) internal {

      // return if zero balance
      if (_balances[user] == 0) {
          return;
      }

      // fetch pending rewards
      uint pending = pendingRewards(user);
      uint bal = IERC20(rewardToken).balanceOf(address(this));
      if (pending > bal) {
          pending = bal;
      }

      // return if no rewards
      if (pending == 0) {
          return;
      }
      
      // reset total rewards
      totalExcluded[user] = getCumulativeDividends(_balances[user]);

      // transfer reward to user
      IERC20(rewardToken).transfer(user, pending);
      emit RewardsClaimed(user, pending);
  }

  /**
   * @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.
   *
   * `_data` is additional data, it has no specified format and it is sent in call to `to`.
   *
   * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
   * implement alternative mechanisms to perform token transfer, such as signature-based.
   *
   * Requirements:
   *
   * - `from` cannot be the zero address.
   * - `to` cannot be the zero address.
   * - `tokenId` token must exist and be owned by `from`.
   * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
   *
   * Emits a {Transfer} event.
   */
  function _safeTransfer(
      address from,
      address to,
      uint256 tokenId,
      bytes memory _data
  ) internal {
      _transfer(from, to, tokenId);
      require(
          _checkOnERC721Received(from, to, tokenId, _data), 
          "ERC721: Transfer to non ERC721Receiver implementer"
      );
  }

  /**
   * @dev Transfers `tokenId` from `from` to `to`.
   *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
   *
   * Requirements:
   *
   * - `to` cannot be the zero address and must be KYC Verified
   * - `tokenId` token must be owned by `from`.
   *
   * Emits a {Transfer} event.
   */
  function _transfer(
      address from,
      address to,
      uint256 tokenId
  ) internal isVerified(to) {
      
      // Ensure State
      require(
          ownerOf(tokenId) == from,
          "ERC721: transfer from incorrect owner"
      );
      require(
          _balances[from] > 0, 
          'Zero Balance'
      );

      // Clear approvals from the previous owner
      _approve(address(0), tokenId);

      // claim rewards for from
      _claimRewards(from);

      // Register Owner If Zero Balance Update
      if (_balances[to] == 0) {
          _registerOwner(to);
      } else {
          _claimRewards(to);
      }

      // Reassign Total Balances
      unchecked {
          _balances[from] -= 1;
          _balances[to] += 1;
      }

      // Reassign Ownership
      _owners[tokenId] = to;

      // Remove Owner If New Balance Is Zero
      if (_balances[from] == 0) {
          _removeOwner(from);
      }

      // reset reward allocations
      totalExcluded[from] = getCumulativeDividends(_balances[from]);
      totalExcluded[to] = getCumulativeDividends(_balances[to]);

      emit Transfer(from, to, tokenId);
  }

  /**
   * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
   * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
   */
  function _safeMint(
      address to,
      uint256 tokenId
  ) internal isVerified(to) {
      _mint(to, tokenId);
      require(
          _checkOnERC721Received(address(0), to, tokenId, ""),
          "ERC721: transfer to non ERC721Receiver implementer"
      );
  }

  /**
   * @dev Mints `tokenId` and transfers it to `to`.
   *
   * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
   *
   * Requirements:
   *
   * - `tokenId` must not exist.
   * - `to` cannot be the zero address.
   *
   * Emits a {Transfer} event.
   */
  function _mint(address to, uint256 tokenId) internal {
      require(!_exists(tokenId), "ERC721: token already minted");
      require(_currentTokenID < nFractions, 'All NFTs Have Been Minted');

      // Register Owner If Zero Balance Update
      if (_balances[to] == 0) {
          _registerOwner(to);
      }

      // set ownership
      _owners[tokenId] = to;

      // increment balance of minter plus the current token ID
      unchecked {
          _balances[to]++;
          _currentTokenID++;
      }

      // set excluded
      totalExcluded[to] = getCumulativeDividends(_balances[to]);

      emit Transfer(address(0), to, tokenId);
      emit Mint(to, tokenId);
  }

  /**
      Registers `owner` in registeredOwner List
   */
  function _registerOwner(address owner) internal {
      _ownerIndex[owner] = _registeredOwners.length;
      _registeredOwners.push(owner);
  }

  /**
      Removes `owner` from registeredOwner List
   */
  function _removeOwner(address owner) internal {

      // set last element index to be removed index
      _ownerIndex[
          _registeredOwners[_registeredOwners.length - 1]
      ] = _ownerIndex[owner];

      // set removed element to be last element
      _registeredOwners[
          _ownerIndex[owner]
      ] = _registeredOwners[_registeredOwners.length - 1];

      // pop off last element
      _registeredOwners.pop();
      delete _ownerIndex[owner];
  }

  /**
   * @dev Approve `to` to operate on `tokenId`
   *
   * Emits a {Approval} event.
   */
  function _approve(address to, uint256 tokenId) internal {
      _tokenApprovals[tokenId] = to;
      emit Approval(ownerOf(tokenId), to, tokenId);
  }

  /**
   * @dev Returns whether `tokenId` exists.
   *
   * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
   */
  function _exists(uint256 tokenId) internal view returns (bool) {
      return _owners[tokenId] != address(0);
  }

  /**
   * @dev Approve `operator` to operate on all of `owner` tokens
   *
   * Emits a {ApprovalForAll} event.
   */
  function _setApprovalForAll(
      address owner,
      address operator,
      bool approved
  ) internal {
      require(
          owner != operator, 
          "Caller Cannot Approve Itself"
      );
      _operatorApprovals[owner][operator] = approved;
      emit ApprovalForAll(owner, operator, approved);
  }

  /**
   * @dev Returns whether `spender` is allowed to manage `tokenId`.
   *
   * Requirements:
   *
   * - `tokenId` must exist.
   */
  function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
      require(
          _exists(tokenId), 
          "Non Existent Token"
      );
      address owner = ownerOf(tokenId);
      return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
  }

  /**
   * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
   * The call is not executed if the target address is not a contract.
   *
   * @param from address representing the previous owner of the given token ID
   * @param to target address that will receive the tokens
   * @param tokenId uint256 ID of the token to be transferred
   * @param _data bytes optional data to send along with the call
   * @return bool whether the call correctly returned the expected magic value
   */
  function _checkOnERC721Received(
      address from,
      address to,
      uint256 tokenId,
      bytes memory _data
  ) private returns (bool) {
      if (to.isContract()) {
          try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
              return retval == IERC721Receiver.onERC721Received.selector;
          } catch (bytes memory reason) {
              if (reason.length == 0) {
                  revert("ERC721: transfer to non ERC721Receiver implementer");
              } else {
                  assembly {
                      revert(add(32, reason), mload(reason))
                  }
              }
          }
      } else {
          return true;
      }
  }

  /**
      Returns A List Of All Accounts With A Fractional Asset Balance Greater Than 0
   */
  function listAllOwners() external view returns (address[] memory) {
      return _registeredOwners;
  }

  /**
      Returns A List Of All Token IDs Belonging To `user`
   */
  function listIDsOwnedByUser(address user) external view returns (uint256[] memory) {
      // If Zero Balance Return Empty List
      uint balance = _balances[user];
      uint256[] memory arr = new uint256[](balance);
      if (balance <= 0) {
          return arr;
      }
      uint count = 0;
      // Loop Through All IDs To Create List
      for (uint i = 0; i < _currentTokenID;) {
          if (_owners[i] == user) {
              arr[count] = i;
              unchecked {
                  ++count;
              }
          }
          unchecked { ++i; }
      }
      return arr;
  }