MorpheusAI

MorpheusAI
Foundry
22,500 USDC
View results
Submission Details
Severity: medium
Invalid

Stakers will lose rewards when the rate calculation round down

Summary

_getCurrentPoolRate() calculates the current rate for a specific pool. If the pool has no deposits, it returns the existing rate. If there are deposits, it calculates the rewards earned in the current period and adjusts the rate accordingly based on the total deposited amount in the pool.

Vulnerability Details

Here is the _getCurrentPoolRate() function implementation:

function _getCurrentPoolRate(uint256 poolId_) private returns (uint256) {
PoolData storage poolData = poolsData[poolId_];
if (poolData.totalDeposited == 0) {
return poolData.rate;
}
uint256 rewards_ = getPeriodReward(poolId_, poolData.lastUpdate, uint128(block.timestamp));
// @audit
return poolData.rate + (rewards_ * PRECISION) / poolData.totalDeposited;
}

A rounding to 0 can occur in the getCurrentPoolRate() function which leads to a loss of rewards for the stakers. With the following values:
`
rewards
= 1e3

PRECISION = 1e18

totalDeposited = 10000*1e18
`
the calculation will round down to 0. The _getCurrentPoolRate is called when stakers stake/withdraw, the pool rate will updated to the new rate and the pool lastUpdate timestamp will be updated to the current timestamp. Thus, stakers rewards will be lost.

The example displays a small value but as the totalDeposited increases, rewards will be lost in the rounding process.

Impact

Stakers will lose rewards when the current rate calculation round to 0.

Tools Used

Manual review

Recommendations

Consider changing the _getCurrentPoolRate implementaion to:

uint256 private dustRewards;
function _getCurrentPoolRate(uint256 poolId_) private returns (uint256) {
PoolData storage poolData = poolsData[poolId_];
if (poolData.totalDeposited == 0) {
return poolData.rate;
}
uint256 rewards_ = getPeriodReward(poolId_, poolData.lastUpdate, uint128(block.timestamp));
if (((rewards_ * PRECISION) / poolData.totalDeposited) == 0) {
dustRewards += rewards_;
return poolData.rate;
}
return poolData.rate + ((rewards_ + dustRewards) * PRECISION) / poolData.totalDeposited;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.