{"content":{"title":"NFT 所有者 tokenID 快速查询","body":"# NFT 所有者 tokenID 快速查询\r\n\r\n最近做项目有一个需求，要求通过用户地址查到用户拥有的 NFT tokenID。由于我做项目向来不高兴写后端，因此考虑使用合约完成这个功能。\r\n\r\n## 实现\r\n\r\n使用合约来查询数据，一般来说有两个方案：存储数据时多用 Gas，查询数据时少用 Gas；或者存储数据时少用 Gas，查询数据时多用 Gas。在目前的场景下，由于存储数据在链上，查询数据不在链上，所以选择第二个方案能更加省 Gas。同时经过我的实测，这个方法可以实现单次 10000 个以上 tokenId 的遍历，对于一般的 NFT 来说足够了。\r\n\r\n```solidity\r\n    function getOwnedTokenIdList(\r\n        address target, // 目标NFT地址\r\n        address owner, // 所有者\r\n        uint256 start, // 起始 tokenId\r\n        uint256 end // 结束 tokenId\r\n    ) external view returns (uint256[] memory tokenIdList) {\r\n        // 起始 tokenId < 结束 tokenId\r\n        require(start < end, \"XenBox: end must over start\");\r\n        IERC721 erc721 = IERC721(target);\r\n        uint256[] memory list = new uint256[](end - start);\r\n        uint256 index;\r\n        // 遍历出所有者拥有的 tokenId\r\n        for (uint256 tokenId = start; tokenId < end; tokenId++) {\r\n            if (erc721.ownerOf(tokenId) == owner) {\r\n                list[index] = tokenId;\r\n                index++;\r\n            }\r\n        }\r\n        // 整理输出数据\r\n        tokenIdList = new uint256[](index);\r\n        for (uint256 i; i < index; i++) {\r\n            tokenIdList[i] = list[i];\r\n        }\r\n    }\r\n```\r\n\r\n这个方法我部署在了 https://etherscan.io/address/0x604995B9377Ac6d9aBbC57b902f6936Df69D01db#readContract ，有兴趣的可以来试试。\r\n\r\n## 优势和缺点\r\n\r\n优势：支持标准的 ERC721，不需要消耗额外的 Gas，也不需要部署后端程序就能实现快速遍历出所有者的 NFT tokenId 。\r\n\r\n缺点：不支持非连续的 tokenId 查询。\r\n\r\n原文发布在 [https://github.com/33357/smartcontract-apps](https://github.com/33357/smartcontract-apps) 这是一个面向中文社区，分析市面上智能合约应用的架构与实现的仓库。欢迎关注开源知识项目！"},"author":{"user":"https://learnblockchain.cn/people/3877","address":"0x1f2479ee1b4aFE789e19D257D2D50810ac90fa59"},"history":null,"timestamp":1672279440,"version":1}