Description:
The FixedRanksReward contract distributes rewards based on predefined ranks (rankedRewards). The current check condition allows the number of winners to be less than the number of ranks set by the session creator:
require(rankedRewards[sessionId].length >= winners.length, GetRewardOutOfRange(sessionId));
This means the system only ensures that there are not more winners than available ranks, but it does not enforce that the number of winners matches the number of ranks.
Since rankedRewards in FixedRanksReward contract's setRankedRewards function is designed such that all its elements together make up 100% of the prize pool (a full BasisPoint):
uint256 totalPoints;
for (uint256 i; i < _rankedRewards.length; ++i) {
totalPoints += _rankedRewards[i];
}
@> require(totalPoints == BASIS_POINTS, InvalidTotalPoints(sessionId, totalPoints));
Any mismatch results in incomplete allocation. If even one rankedRewards element remains unused (because fewer winners are provided), part of the prize pool remains undistributed.
A practical case occurs when a session start date is extended by the creator and some participants leave, reducing the final number of winners below the configured ranks. As a result, a portion of the prize pool remains stuck in the contract with no mechanism to recover or reallocate it.
Impact:
Mitigation:
Enforce that rankedRewards[sessionId].length == winners.length to ensure complete distribution.
Attack Scenario:
rankedRewards with, e.g., 5 ranks (100%, distributed as portions).rankedRewards.length (5) >= winners.length (3).