Beatland Festival

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

Gas optimization for getUserMemorabiliaDetailed

Description

While view functions are designed for fortends use, it is still best practice to optimize for gas. Nodes can revert RPC calls to view functions if it cost too much, while this behavior is not defined standard, still some noted can reject the request.

Recommended Mitigation

Option 1: optimize second loop

In getUserMemorabiliaDetailed the second loop does not need to iterate over all collections and items, we know how many items the user have from the first loop.

function getUserMemorabiliaDetailed(address user) external view returns (
uint256[] memory tokenIds,
uint256[] memory collectionIds,
uint256[] memory itemIds
) {
// Use dynamic arrays to collect data in single pass
uint256[] memory tempTokenIds = new uint256[](10000); // Reasonable upper bound
uint256[] memory tempCollectionIds = new uint256[](10000);
uint256[] memory tempItemIds = new uint256[](10000);
uint256 count = 0;
// Single pass through all collections and items
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) {
tempTokenIds[count] = tokenId;
tempCollectionIds[count] = cId;
tempItemIds[count] = iId;
count++;
}
}
}
// Create properly sized arrays and copy data
tokenIds = new uint256[](count);
collectionIds = new uint256[](count);
itemIds = new uint256[](count);
for (uint256 i = 0; i < count; i++) {
tokenIds[i] = tempTokenIds[i];
collectionIds[i] = tempCollectionIds[i];
itemIds[i] = tempItemIds[i];
}
return (tokenIds, collectionIds, itemIds);
}

Option 2: Implement a mapping

If we expect getUserMemorabiliaDetailed to be frequently used, it is better to collect data at time of mint/burn/transfer. The performance will be O(1) instead of O(n).

  • userOwnedTokens mapping: Tracks all tokenIds owned by each user

  • userTokenIndex mapping: Provides O(1) lookup for token updates


mapping(address => uint256[]) private userOwnedTokens;
mapping(address => mapping(uint256 => uint256)) private userTokenIndex;
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.