Beatland Festival

First Flight #44
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: low
Likelihood: high
Invalid

Unnecessary gas usage in `getUserMemorabiliaDetailed` function

Description

The function getUserMemorabiliaDetailed(address user) is used to fetch all memorabilia NFTs a user owns by checking each item in every collection. However, it uses two nested loops:

  1. The first loop iterates over all collection and item IDs to count how many tokens the user owns.

  2. The second loop repeats the exact same iteration to populate the arrays with matching token IDs and details.

This double iteration is redundant and gas-inefficient, especially as the number of collections and items grows. Every call to balanceOf(user, tokenId) is also expensive, and the function calls it twice per item.

//!nested loops
uint256 index = 0;
for (uint256 cId = 1; cId < nextCollectionId; cId++) {
for (uint256 iId = 1; iId < collections[cId].currentItemId; iId++) {
uint256 tokenId = encodeTokenId(cId, iId);
if (balanceOf(user, tokenId) > 0) {
tokenIds[index] = tokenId;
collectionIds[index] = cId;
itemIds[index] = iId;
index++;
}
}
}
// First, count how many memorabilia they own
//!nested loops
uint256 count = 0;
for (uint256 cId = 1; cId < nextCollectionId; cId++) {
for (uint256 iId = 1; iId < collections[cId].currentItemId; iId++) {
uint256 tokenId = encodeTokenId(cId, iId);
if (balanceOf(user, tokenId) > 0) {
count++;
}
}
}

Risk

HIGH :

  • No external condition required

Likelihood:

HIGH :

  • Iteratration over every possible tokenId, even ones no one owns.

  • Calling balanceOf(user, tokenId) many times (very expensive in large collections).

  • No mapping from users to owned token IDs exists.

Impact:

  • Out of gas errors

  • High gas consuming functions

Recommended Mitigation

  • Use mappings to reduce double loops calls

  • Track the actual count with an index.

mapping(address => uint256[]) internal userTokenIds;
mapping(uint256 => uint256) internal tokenIdToCollectionId;
mapping(uint256 => uint256) internal tokenIdToItemId;
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.