Normal behaviour: getUserMemorabiliaDetailed(user) should return arrays of all memorabilia token IDs owned by a user.
Issue: The function iterates over every item ever minted across all collections, using nested for loops and calling balanceOf on each candidate ID. As collections and items grow, the loop count increases linearly until the call exceeds the block gas limit or RPC timeouts, rendering the function unusable.
Likelihood:
Each new memorabilia drop increases iteration count; gas grows continuously during normal festival operations.
Eventually the function will hit block gas limits even for a single owner query.
Impact:
Denial of Service: on-chain contracts can no longer call the function.
Off-chain callers (front-ends) experience RPC timeouts; users cannot view their collections.
A full on-chain reproduction would require millions of items, so the PoC is expressed conceptually:
Assume the festival has issued 5 000 collections with 500 memorabilia items each (reasonable after several years). That equals 2.5 million loop iterations.
Any contract or user calls getUserMemorabiliaDetailed(user).
The EVM must iterate through 2.5 million balanceOf checks; gas usage exceeds the block gas limit and the transaction reverts, denying service.
Maintain a lightweight index that is updated as tokens move, making enumeration O(ownedTokens) instead of O(totalTokens). Example pattern:
This design bounds gas to the number of items actually owned by the caller—typically a few dozen—eliminating the DoS vector.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.