MorpheusAI

MorpheusAI
Foundry
22,500 USDC
View results
Submission Details
Severity: low
Valid

The `editPool()` lacks a sanity check on the `payoutStart` parameter leading to incorrect or unfair reward distributions

Summary

An admin can update the core parameters of a specific pool via the Distribution:editPool(). However, the function lacks a sanity check on the payoutStart parameter, leading to incorrect or unfair reward distributions to pool stakers.

Vulnerability Details

The snippet below presents the editPool(). As you can see, the function does not have a sanity check on the pool_.payoutStart parameter. Therefore, the pool_.payoutStart parameter can be set to an arbitrary timestamp, including the past timestamp.

Suppose the past timestamp is set by mistake. The pool will distribute rewards to stakers by accounting for past staking positions, which can lead to incorrect or unfair reward distribution issues for some stakers.

To elaborate, for instance, if some stakers had unstaked their staking positions before the pool in question was updated, they would lose the rewards even if the reward distribution also accounts for the period of time they had ever staked in the pool. In other words, the pool should not distribute rewards to past staking positions for fair distributions.

function editPool(uint256 poolId_, Pool calldata pool_) external onlyOwner poolExists(poolId_) {
_validatePool(pool_);
require(pools[poolId_].isPublic == pool_.isPublic, "DS: invalid pool type");
PoolData storage poolData = poolsData[poolId_];
uint256 currentPoolRate_ = _getCurrentPoolRate(poolId_);
// Update pool data
poolData.rate = currentPoolRate_;
poolData.lastUpdate = uint128(block.timestamp);
pools[poolId_] = pool_;
emit PoolEdited(poolId_, pool_);
}
  • https://github.com/Cyfrin/2024-01-Morpheus/blob/07c900d22073911afa23b7fa69a4249ab5b713c8/contracts/Distribution.sol#L82-L96

Impact

Distributing rewards by accounting for past staking positions can lead to incorrect or unfair reward distribution issues for some stakers.

For instance, if some stakers had unstaked their staking positions before the pool was updated, they would lose the rewards even if the reward distribution also accounts for the period of time they had ever staked in the pool. In other words, the pool should not distribute rewards to past staking positions for fair distributions.

Tools Used

Manual Review

Recommendations

Add a sanity check on the pool_.payoutStart parameter, like the below snippet. The sanity check ensures that the pool cannot distribute rewards to past staking positions for fair reward distributions.

function editPool(uint256 poolId_, Pool calldata pool_) external onlyOwner poolExists(poolId_) {
+ require(pool_.payoutStart > block.timestamp, "DS: invalid payout start value");
_validatePool(pool_);
require(pools[poolId_].isPublic == pool_.isPublic, "DS: invalid pool type");
PoolData storage poolData = poolsData[poolId_];
uint256 currentPoolRate_ = _getCurrentPoolRate(poolId_);
// Update pool data
poolData.rate = currentPoolRate_;
poolData.lastUpdate = uint128(block.timestamp);
pools[poolId_] = pool_;
emit PoolEdited(poolId_, pool_);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

`editPool` function doesn't do the payoutStart check

serialcoder Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

`editPool` function doesn't do the payoutStart check

Support

FAQs

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