如何查找NFT集合的所有者计数?



我试图找到一个NFT集合持有人计数(ERC721令牌)。例如,OpenSea和EtherScan有这些数据,但我找不到原生ERC721方法来实现这一点。

做这件事的最好方法是什么?

谢谢

嗯,经过几个小时的研究,我找到了一些解决方案,想分享给大家。

有以下几种方法:

  1. 如果你正在处理一个特定的合同,而这个合同扩展了ERC721Enumerable,那么你的案例研究就容易一些。因为可以使用totalSupply()找到令牌计数,所以可以跳过下面代码的第一部分。
  2. 如果你想使用第三方工具,你可能想检查Moralis。它返回所有者计数、地址列表和额外数据。查看已经存在的答案
  3. 如果你想手动编写代码,这里是我的代码:

async testGetOwnerCount({ }, payload) {
// Connect the contract 
let nftContract = new ethers.Contract(nftContractAddress, ERC721.abi, signer);
// First find the mint count which is equal to the token count
const transferFilter = nftContract.filters.Transfer("0x0000000000000000000000000000000000000000", null, null)
const tokens = await nftContract.queryFilter(transferFilter)
const tokenCount = tokens.length;
// Iterate over tokens and store owner addresses in an array
let owners = []
for (let i = 0; i < tokenCount; i++) {
// First, find the all transfers of the token 
// from null` to `null` so we get all the transfers of `tokenId` 
const transferFilter = nftContract.filters.Transfer(null, null, parseInt(tokens[i].args.tokenId))
const tokenTransfers = await nftContract.queryFilter(transferFilter)
// `args.to` of the last element gives the current owner of issued token
let lastTransfer = tokenTransfers[tokenTransfers.length - 1]
let currentOwner = lastTransfer.args.to
// If the address has already found before, don't add it...
if (!owners.includes(currentOwner)) {
owners.push(currentOwner)
}
}
}

可能有更好的方法来实现这一点,但这是我能找到的最好的方法,因为我想处理所有的合同,不仅是那些ERC721Enumerable,而且不想使用其他工具。

最好的方法是使用Transfer事件,因为这就是它的作用。您可以查询所有传输事件,并按ID进行过滤。

然而,你也可以创建你的自定义function(id, address),它将在每次nft传输时被调用,在那里你可以将其推送到映射id -> address[]中的数组中,该数组表示拥有该nft的用户的地址。

然后创建另一个function(id),根据发送给函数的id返回该数组。

您不需要任何第三方合同或服务。您可以设置3个映射:

// each operation on mapping takes O(1) time
//keep track of how many tokens each address have
mapping(address => uint256) private ownedTokens
// from tokenId=>ownerAddress
// keep track of owner of each tokenId
mapping(uint256 => address) private tokenOwner
// keep track of how many tokens does an address own
mapping(address => uint256) private ownedTokensCount

映射对于优化代码非常有用。当您编写mint函数时,您必须相应地更新这些映射。

function mint(address to, uint256 tokenId) external {
// ADD YOUR REQUIRE LOGIC
ownedTokensCount[to] += 1;
tokenOwner[tokenId] = to;
ownedTokens[to] = tokenId;
}