Submitted by BugBusters
https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/miner/stakerewardV2pool.sol#L132-L150 https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/miner/ProtocolRewardsPool.sol#L227-L240 https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/miner/EUSDMiningIncentives.sol#L226-L242
Rewards in the synthetix derivative contracts (EUSDMinningIncentives.sol, ProtocolRewardsPool.sol and stakerRewardsV2Pool.sol) are initiated when the owner calls the notifyRewardAmount. This function calculates the reward rate per second and also records the start of the reward period. This has an edge case where rewards are not counted for the initial period of time until there is at least one participant.
Look at the code for stakerrewardV2Pool.sol (other files have somewhat similar logic too), derived from the synthetix:
The intention here, is to calculate how many tokens should be rewarded by unit of time (second) and record the span of time for the reward cycle. However, this has an edge case where rewards are not counted for the initial period of time until there is at least one participant (in this case, a holder of BathTokens). During this initial period of time, the reward rate will still apply but as there isnt any participant, then no one will be able to claim these rewards and these rewards will be lost and stuck in the system.
This is a known vulnerability that has been covered before. The following reports can be used as a reference for the described issue:
As described by the 0xmacro blogpost, this can play out as the following:
Lets consider that you have a StakingRewards contract with a reward duration of one month seconds (2592000):
Block N Timestamp = X
You call notifyRewardAmount() with a reward of one month seconds (2592000) only. The intention is for a period of a month, 1 reward token per second should be distributed to stakers.
Block M Timestamp = X + Y
Y time has passed and the first staker stakes some amount:
Hence, for this staker, the clock has started from X+Y, and they will accumulate rewards from this point.
Please note, that the periodFinish is X + rewardsDuration, not X + Y + rewardsDuration. Therefore, the contract will only distribute rewards until X + rewardsDuration, losing  Y * rewardRate => Y * 1  inside of the contract, as rewardRate = 1 (if we consider the above example).
Now, if we consider delay (Y) to be 30 minutes, then:
Only 2590200 (2592000-1800) tokens will be distributed and these 1800 tokens will remain unused in the contract until the next cycle of notifyRewardAmount().
Manual Review
A possible solution to the issue would be to set the start and end time for the current reward cycle when the first participant joins the reward program (i.e. when the total supply is greater than zero) instead of starting the process in the notifyRewardAmount.
0xean (judge) decreased severity to Medium
LybraFinance confirmed
