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];
}
Transfer
events and filter it by receiving address.