#41664 [SC-Low] Users may receive fewer rewards due to the change in reward limits

Submitted on Mar 17th 2025 at 12:22:20 UTC by @zaevlad for Audit Comp | Yeet

  • Report ID: #41664

  • Report Type: Smart Contract

  • Report severity: Low

  • Target: https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/Reward.sol

  • Impacts:

    • Permanent freezing of unclaimed yield

Description

Brief/Intro

The max reward amount is based on the calculation of epoch rewards and MAX_CAP_PER_WALLET_PER_EPOCH_FACTOR value. If its value will be changed, users may get less rewards than expected.

Vulnerability Details

After every game users can claim thier rewards by clalling claim() in the REwards contract.

The function defines the max reward amount and max aount that can be claimed by a user:

    function getClaimableAmount(address user) public view returns (uint256) {
        uint256 totalClaimable;

        // Fixed-point arithmetic for more precision
        uint256 scalingFactor = 1e18;

        for (uint256 epoch = lastClaimedForEpoch[user] + 1; epoch < currentEpoch; epoch++) {
            if (totalYeetVolume[epoch] == 0) continue; // Avoid division by zero

            uint256 userVolume = userYeetVolume[epoch][user];
            uint256 totalVolume = totalYeetVolume[epoch];

            uint256 userShare = (userVolume * scalingFactor) / totalVolume;

@>          uint256 maxClaimable = (epochRewards[epoch] / rewardsSettings.MAX_CAP_PER_WALLET_PER_EPOCH_FACTOR());
            uint256 claimable = (userShare * epochRewards[epoch]) / scalingFactor;

            if (claimable > maxClaimable) {
@>             claimable = maxClaimable;
            }

            totalClaimable += claimable;
        }

        return totalClaimable;
    }

MAX_CAP_PER_WALLET_PER_EPOCH_FACTOR is a base value for each epoch that can be changed in the RewardsSettings contract. The default value is 30. This means that the maximum claimable amount for each user cannot exceed 30% of the total amount for the epoch.

From a functional point of view, there is no mechanism in the code to carry over 'surpluses' to the next epoch. So any unclaimed rewards are lost.

Also there is no requirement for the user to call the claim() function after the epoch ends. He can wait for several epochs to end to get rewards from all of them.

If MAX_CAP_PER_WALLET_PER_EPOCH_FACTOR is changed to a lower value, such as 25, users will lose a portion of their rewards forever.

Impact Details

Users may receive fewer rewards due to the change in reward limits, and these rewards will be lost.

References

https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/RewardSettings.sol#L41 https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/Reward.sol#L187

Proof of Concept

Proof of Concept

Let's make a simple example:

Alice: 500 YEET
Bob: 300 YEET
Rob: 200 YEET

epochRewards[epoch] = 1000 tokens
MAX_CAP_PER_WALLET_PER_EPOCH_FACTOR = 2 (maxClaimable = 500)

For Alice the amount of rewards can be the max amount and she will not loose anything:

Alice:
userShare = (500 * 1e18) / 1000 = 0.5e18
claimable = (0.5e18 * 1000) / 1e18 = 500 tokens
maxClaimable = 1000 / 2 = 500 tokens

Finaly Alice gets 500 tokens 

However if the MAX_CAP_PER_WALLET_PER_EPOCH_FACTOR will be cahnged to 3:

maxClaimable = 1000 / 3 = 333 tokens

Alice will get 333 tokens instead of 500. So she looses 167 reward tokens.

And this amount will be lost forever. If she's trying to claim rewards for more than one epoch, the amount lost may be higher.

Consider storing the MAX_CAP_PER_WALLET_PER_EPOCH_FACTOR separately for each epoch.

Was this helpful?