<!-- canonical: https://0xsimao.com/findings/exactly-protocol-update-staking-contract-reward-release-rewards-timestamp -->

# `rewardData.releaseRate` is incorrectly calculated on `RewardsController::config()` when `block.timestamp > start` and `rewardData.lastConfig != rewardData.start`

Medium · Sherlock · Staking · 22nd April 2024

Finding M-16 of the Exactly Protocol Update - Staking Contract competition.

- Protocol: https://audits.sherlock.xyz/contests/247
- Source: https://github.com/sherlock-audit/2024-04-interest-rate-model-judging/issues/245

---

## Summary

Setting new parameters in `RewardsController::config()` will lead to lost rewards if `block.timestamp > start` and the `rewardData.start` was set in the future initially.

## Vulnerability Detail

When `RewardsController::config()` is called to update the data of a reward, as it was already set initially, it will go into the `else` branch. In here, it updates the `rewardRate` according to the previously distributed rewards, the total distribution and the distribution periods. More precisely, the calculation is:
```solidity
...
if (block.timestamp > start) {
  released =
    rewardData.lastConfigReleased +
    rewardData.releaseRate *
    (block.timestamp - rewardData.lastConfig);
  elapsed = block.timestamp - start;
  if (configs[i].totalDistribution <= released || configs[i].distributionPeriod <= elapsed) {
    revert InvalidConfig();
  }
  rewardData.lastConfigReleased = released;
}

rewardData.releaseRate =
  (configs[i].totalDistribution - released) /
  (configs[i].distributionPeriod - elapsed);
...
``` 
It calculates the release pro-rata to `block.timestamp - rewardData.lastConfig`, considering the time that the rewards have been emitted, but this is incorrect when `rewardData.start` was set in the future when creating the initial config. This will lead to the overestimation of released rewards, which will lower the `rewardData.releaseRate`, as it is pro-rata to `configs[i].totalDistribution - released`. Thus, less rewards will be distributed than expected.

## Impact

Lost of rewards for users that will receive less than supposed.

## Code Snippet

https://github.com/sherlock-audit/2024-04-interest-rate-model/blob/main/protocol/contracts/RewardsController.sol#L681
https://github.com/sherlock-audit/2024-04-interest-rate-model/blob/main/protocol/contracts/RewardsController.sol#L699

## Tool used

Manual Review

Vscode

## Recommendation

The release rewards are `rewardData.releaseRate * (block.timestamp - rewardData.start);`.

---

Related findings:

- [feesAccrued or staker principal may be sent as rewards if rewardRate and emissionEnd are not properly calculated](https://0xsimao.com/findings/metazero-ii-fees-rewards-reward-properly): MetaZero Staking
- [The health of a ```ProtectedListing``` is incorrectly calculated if the ```tokenTaken``` has be changed through ```ProtectedListings::adjustPosition()```.](https://0xsimao.com/findings/flayer-health-through-listings-adjust): Flayer
- [Setting maxFundingFeePerBlock to a lower value than abs(lastFundingRate) will brick getPendingAccFundingFees()](https://0xsimao.com/findings/ostium-fee-abs-brick-fees): Ostium
- [Rewards are calculated as distributed even if there are no stakers, locking the rewards forever](https://0xsimao.com/findings/zivoe-rewards-distributed-stakers-locking): Zivoe
