The LSTRewardsSplitterController
contract contains an unbounded loop in its checkUpkeep
and performUpkeep
functions. As the number of reward splitters increases, these functions may exceed the block gas limit or become too expensive to call. It is generally not a good practice to loop through an unbounded loop.
The checkUpKeep
function retuns a bytes variable representing an array of booleans, whether to call performUpKeep
on the given splitter or not. However the checkUpKeep
function iterates through all of the splitters that are in the storage array accounts
and mapping splitters
. This number could grow to a number that is too big either hiting the block gas limit or causing the function performUpKeep
to be too expensive to be called. On the other hand if any of the splitters's performUpKeep
function reverts this will cause the whole function to revert, causing a DoS once again. For example if this condition is met - (uint256(newRewards) < controller.rewardThreshold())
the function will revert with InsufficientRewards()
.
Reward distributions could be delayed or fail entirely, affecting user returns and trust in the protocol.
The performUpKeep
function can either hit the block gas limit or become too expensive to be called. This will make the function unusable.
Manual Review
Modify the checkUpkeep and performUpkeep functions to process a limited number of splitters per transaction. Implement a mechanism to track which splitters have been processed and continue from that point in subsequent calls.
Batch Processing: Implement a maximum batch size for processing splitters in a single transaction.
Tracking: Implement a more gas-efficient way to track which splitters need upkeep, such as using a bitmap or a separate queue for splitters needing processing.
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.