I have created a smart contract where users can mint several ERC721 tokens.

I used the ERC721Enumerable extension from OpenZeppelin so I can easily retrieve which tokens have been minted by a specific address. From their documentation, this Solidity function returns the token ID at a specific index:

tokenOfOwnerByIndex(address owner, uint256 index) → uint256

I have no issue using the function in a loop with Python (I'm using Brownie for testing purpose):

balance = enumerable.balanceOf(account)
items = []
for i in range(0, balance):
   items.append(enumerable.tokenOfOwnerByIndex(account, i))

And I can even do the same with a React Front-end by using the following:

import { useContractFunction, useEthers, useContractCall } from "@usedapp/core"
const [tokenId]: any = useContractCall({
    abi: TimeCollectibleInterface,
    address: TimeCollectibleContractAddress,
    method: "tokenOfOwnerByIndex",
    args: [address, 0],
    }) ?? [];

The problem is that this hook only return one token ID the user has minted at a time. In this case it returns the token Id for "address" at position "0", as specified in the function args.

In my specific case, the user can mint up to 60 tokens (for instance: from tokenId=60 to 99 and from tokenId=110 to 119). My idea was thus to use this hooks in a loop (so looping from index=0 to index=balance of the user) but it seems it's not possible to use hooks together with loops in React.

Any idea? Thanks!

1 Answer 1


Looks I solved the issue by myself by using the useCalls function from useDapp instead of useContractCall.

First I get the number of ERC721 tokens the user has in his balance :

    const [userBalance]: any = useContractCall({
        abi: TimeCollectibleInterface,
        address: TimeCollectibleContractAddress,
        method: "balanceOf",
        args: [address],
        }) ?? [0];

    var balanceItems = Array.from(Array(Number(userBalance)).keys())

I then use the useCalls to call each item at a time :

    const results = useCalls(
          ? balanceItems.map((idx: any) => ({
              contract: new Contract(TimeCollectibleContractAddress, TimeCollectibleInterface),
              method: 'tokenOfOwnerByIndex',
              args: [userAddress, idx],
          : []

This ends up by returning an [object object] with the different items owned by the user. Might not be the best looking solution, but at least it works!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.