It depends on the contract implementation. How the developer keeps track of the owner: This is one way you can implement it:
mapping(address=>mapping(uint=>uint)) private _ownedTokens;
this mapping is like:
{"0x32j23h32h423.....":{1:tokenId-1 , 2:tokenId-2}}
Have another mapping for a fast lookup:
// id => index mapping(uint=> uint) private _idToOwnedIndex;
Then define a function to update the state of owner:
function _addTokenToOwner(address to, uint tokenId) private{ uint length=ERC721.balanceOf(to); _ownedTokens[to][length]=tokenId; _idToOwnedIndex[tokenId]=length; }
call _addTokenOwner() in _beforeTokenTransfer()
function _beforeTokenTransfer(address from, address to,uint tokenId)internal virtual override{ // in case this is provided in super contract, the contract that you are extending from call this super._beforeTokenTransfer(from,to,tokenId); // that means we are minting the token // Becasue inside ERC721._mint we call _beforeTokenTransfer(address(0),to,tokenId) if(from==address(0)){ _addTokenToAllTokens(tokenId); } // this also satisfied when we mint the token. if (to!=from){ _addTokenToOwner(to, tokenId); } }
Now write the function to get the NFTs that msg.sender owns. I don't think you should implement a way to view other account's NFTs.
function getOwnedNfts() public view returns(NftItem[] memory){ uint ownedItemsCount=ERC721.balanceOf(msg.sender); NftItem[] memory items= new NftItem[](ownedItemsCount); for (uint i=0; i<ownedItemsCount; i++){ uint tokenId=tokenOfOwnerByIndex(msg.sender, i); NftItem storage item=_idToNftItem[tokenId]; items[i]=item; } return items; }
This is the helper function used in the getOwnedNfts() function:
function tokenOfOwnerByIndex(address owner,uint index) public view returns(uint){ require(index<ERC721.balanceOf(owner), "Index out of bounds"); return _ownedTokens[owner][index]; }
Transferevents and filter it by receiving address.