/* Consumer SPDX-License-Identifier: CC0-1.0 */ pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "./IERC721Holder.sol"; /** * @title Consumer * * @notice this contract implements an example "consumer" of the proposed * held token ERC standard. * This example consumer contract will query ERC721 ownership and balances * including any "held" tokens */ contract Consumer { using Address for address; // members IERC721 public token; /** * @param token_ address of ERC721 token */ constructor(address token_) { token = IERC721(token_); } /** * @notice get the functional owner of a token * @param tokenId token id of interest */ function getOwner(uint256 tokenId) external view returns (address) { // get raw owner address owner = token.ownerOf(tokenId); // if owner is not contract, return if (!owner.isContract()) { return owner; } // check for token holder interface support try IERC165(owner).supportsInterface(0x16b900ff) returns (bool ret) { if (!ret) return owner; } catch { return owner; } // check for held owner try IERC721Holder(owner).heldOwnerOf(address(token), tokenId) returns (address user) { if (user != address(0)) return user; } catch {} return owner; } /** * @notice get the total user balance including held tokens * @param owner user address * @param holders list of token holder addresses */ function getBalance(address owner, address[] calldata holders) external view returns (uint256) { // start with raw token balance uint256 balance = token.balanceOf(owner); // consider each provided token holder contract for (uint256 i = 0; i < holders.length; i++) { balance += IERC721Holder(holders[i]).heldBalanceOf(address(token), owner); } return balance; } }