MorpheusAI

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

LinearDistributionIntervalDecrease library logic error in calculating fullPeriodReward will lead to protocol losing funds

Vulnerability Details

In LinearDistributionIntervalDecrease::_calculateFullPeriodReward

function _calculateFullPeriodReward(
uint128 payoutStart_,
uint128 startTime_,
uint128 endTime_,
uint128 interval_,
uint256 initialAmount_,
uint256 decreaseAmount_
) private pure returns (uint256) {
// START calculate initial reward when period start
uint256 timePassedBefore_ = startTime_ - payoutStart_;
uint256 intervalsPassedBefore_ = _divideCeil(timePassedBefore_, interval_);//@audit first round up
uint256 decreaseRewardAmount_ = intervalsPassedBefore_ * decreaseAmount_;
if (decreaseRewardAmount_ >= initialAmount_) {
return 0;
}
uint256 initialReward_ = initialAmount_ - decreaseRewardAmount_;
// END
// Intervals passed
uint256 ip_ = ((endTime_ - payoutStart_ - intervalsPassedBefore_ * interval_) / interval_);//@audit should not used here again
if (ip_ == 0) {
return 0;
}
return initialReward_ * ip_ - (decreaseAmount_ * (ip_ * (ip_ - 1))) / 2;
}

The function calculates the reward for the part of the specified period that is not partitioned i.e. the part represents an integer number of intervals.
The function first calculate intervalsPassedBefore_ rounding the number Up, then calculate decreaseRewardAmount_ based on the rounded-up intervals,
Then have initialReward_ as:
initialReward_ = initialAmount_ - decreaseRewardAmount_;
finally, the number of full intervals of this part the formula was:
uint256 ip_ = ((endTime_ - payoutStart_ - intervalsPassedBefore_ * interval_) / interval_);

to understand the impact of these multiple rounding let's consider the following scenario, which uses very simplified numbers only for declaration:
Assume we have:
payoutStart = 1
startTime = 2.5
endTime = 6
interval_ = 1
decreaseAmount_ = 5
initialAmount_ =100
The calculations go like :

  • uint256 timePassedBefore_ = startTime_ - payoutStart_;
    timePassedBefore_ = 2.5 - 1 = 1.5 ->( round down to 1)

  • uint256 intervalsPassedBefore_ = divideCeil(timePassedBefore, interval_);

  • function divideCeil(uint256 a, uint256 b_) private pure returns (uint256) {
    return (a_ + b_ - 1) / b_;
    }
    Then, intervalspassedBefore_ = timePassedBefore_ + interval_ -1 / interval_;
    timePassedBefore_ = 1 + 1 -1 / 1 = 1 // one whole interval passed

  • uint256 decreaseRewardAmount_ = intervalsPassedBefore_ * decreaseAmount_;
    decreaseRewardAmount_ = 1 * 5 = 5

  • uint256 initialReward_ = initialAmount_ - decreaseRewardAmount_;
    initialReward_ = 100 - 5 = 95 // which is more than it should in the beginning of the first whole interval

  • uint256 ip_ = ((endTime_ - payoutStart_ - intervalsPassedBefore_ * interval_) / interval_);
    ip_ = ((6-1-1*1)/1) = 4 // the period contains full 4 intervals, which is not correct as it contains only 3

  • return initialReward_ * ip_ - (decreaseAmount_ * (ip_ * (ip_ - 1))) / 2;
    in our example return 95* 4-( 5* (4*(4-1)))/2
    That is the expected reward for the full period=350
    While if we do the math in this simple example it should've been 90 + 85 =80 = 225 only

Impact

This will lead to giving bigger rewards for the users than it should and leads to loss of protocol's balance.

Tools Used

Manual review

Recommendations

- uint256 ip_ = ((endTime_ - payoutStart_ - intervalsPassedBefore_ * interval_) / interval_);
+ uint256 ip_ = ((endTime_ - startTime_) / interval_);

this will round-down correctly adjusting the calculations.

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
Heba Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
Heba Submitter
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.