Beatland Festival

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

[ H-1] - Unbounded Loop in `getUserMemorabiliaDetailed` + Denial of Service (DoS) Impact

Unbounded Loop in getUserMemorabiliaDetailed + Denial of Service (DoS) Impact

Description

  • Normally, a view function like getUserMemorabiliaDetailed is expected to return a user's memorabilia efficiently, regardless of the number of collections or items.

  • In this implementation, the function uses nested loops to iterate over every memorabilia collection and every item within each collection, performing a balanceOf check for each. As the number of collections and items grows, the function's gas usage increases quadratically.

function getUserMemorabiliaDetailed(address user) public view returns (Memorabilia[] memory) {
uint256 count;
for (uint256 cId = 1; cId <= totalCollections; ++cId) {
for (uint256 iId = 1; iId <= collections[cId].currentItemId; ++iId) {
@> if (balanceOf(user, getTokenId(cId, iId)) > 0) {
++count;
}
}
}
// ... (rest of function)
}

Risk

Likelihood:

  • This will occur as soon as the number of memorabilia collections and items grows beyond a trivial amount.

  • Any active festival with ongoing memorabilia redemptions will eventually hit the block gas limit, making the function unusable.

Impact:

  • The function will become permanently unusable, causing a Denial of Service for any user or dApp that relies on it.

  • Off-chain services and users will be unable to retrieve memorabilia data, breaking user experience and integrations.

Proof of Concept

The following scenario demonstrates the issue: as more memorabilia collections and items are created, the function's gas usage increases until it exceeds the block gas limit.

// Pseudocode: After many collections/items, this call will revert due to out-of-gas
getUserMemorabiliaDetailed(userAddress); // reverts with "out of gas"

Recommended Mitigation

This type of data aggregation should be handled off-chain. Remove the function and rely on event indexing for memorabilia tracking.

- function getUserMemorabiliaDetailed(address user) public view returns (Memorabilia[] memory) {
- // ... unbounded nested loops ...
- }
+ // Remove this function. Use off-chain event listeners to aggregate memorabilia data.
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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