It seems that the mainNft
contract you're instantiating hasn't extended the ERC721Enumerable
contract in its implementation.
It would work fine if the NFT contract being created inherits/extends the ERC721Enumerable
contract like this:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {IERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import {ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
contract MyNFT is ERC721Enumerable {
constructor(string memory name, string memory symbol)
ERC721(name, symbol)
{}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
}
contract MyNFTCount {
IERC721Enumerable public mainNft;
constructor(address myNFTAddress) {
mainNft = IERC721Enumerable(myNFTAddress);
}
function viewOwnerNFTBalance(address _owner)
public
view
returns (uint256 balanceOfOwner)
{
return mainNft.balanceOf(_owner);
}
function getTokenIdOfOwnerByIndex(address _owner, uint256 index)
public
view
returns (uint256)
{
return mainNft.tokenOfOwnerByIndex(_owner, index);
}
function getTokenIdsOfOwner(address _owner)
public
view
returns (uint256[] memory tokensOfOwner)
{
uint256 _len = mainNft.balanceOf(_owner);
uint256[] memory _tokensOfOwner = new uint256[](_len);
for (uint256 i = 0; i < _len; i++) {
_tokensOfOwner[i] = mainNft.tokenOfOwnerByIndex(_owner, i);
}
return _tokensOfOwner;
}
}
If the NFT contract is a simple ERC721
(i.e., not extending the ERC721Enumerable
), then one way to get the token ids owned by an address is to fetch and filter the logs of the corresponding NFT contract.
Here's a minimal JS code (created by following this hardhat implementation) to achieve the same:
const { ethers } = require('ethers');
const provider = new ethers.JsonRpcProvider("JSON_RPC_URL");
const ERC721 = require('@openzeppelin/contracts/build/contracts/ERC721.json');
async function listTokensOfOwner(tokenAddress, account) {
const token = new ethers.Contract(
tokenAddress,
ERC721.abi,
provider,
);
const sentLogs = await token.queryFilter(
token.filters.Transfer(account, null),
);
const receivedLogs = await token.queryFilter(
token.filters.Transfer(null, account),
);
const logs = sentLogs.concat(receivedLogs)
.sort(
(a, b) =>
a.blockNumber - b.blockNumber ||
a.transactionIndex - b.transactionIndex,
);
const owned = new Set();
for (const { args: { from, to, tokenId } } of logs) {
if (addressEqual(to, account)) {
owned.add(tokenId.toString());
} else if (addressEqual(from, account)) {
owned.delete(tokenId.toString());
}
}
return owned;
};
function addressEqual(a, b) {
return a.toLowerCase() === b.toLowerCase();
}
async function getTokenName(tokenAddress) {
const token = new ethers.Contract(
tokenAddress,
ERC721.abi,
provider,
);
return token.name();
}
async function main(token, account) {
console.log(await getTokenName(token), 'tokens owned by', account);
const owned = await listTokensOfOwner(token, account);
console.log([...owned].join('\n'));
};
main("NFT_CONTRACT_ADDRESS", "WALLET_ADDRESS")