MorpheusAI

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

Potential Temporary Fund Lock Due to Contract Balance Falling Below Minimal Stake in the `Distribution` contract

Summary

The _withdraw() function in the Distribution contract contains logic that could lead to a situation where users are unable to withdraw their funds if the contract's balance of the depositToken falls below the minimal stake amount required for public pools.

Vulnerability Details

The _withdraw() function in the Distribution contract performs a check to adjust the withdrawal amount to the contract's balance if the requested withdrawal amount exceeds the available balance.

uint256 depositTokenContractBalance_ = IERC20(depositToken).balanceOf(address(this));
if (amount_ > depositTokenContractBalance_) {
amount_ = depositTokenContractBalance_;
}

https://github.com/Cyfrin/2024-01-Morpheus/blob/76898177fbedcbbf4b78b513d9fa151bbf3388de/contracts/Distribution.sol#L250C1-L253C14

Subsequently, it enforces a rule that the remaining staked amount after withdrawal must be either zero or at least equal to the minimal stake amount.

newDeposited_ = deposited_ - amount_;
require(amount_ > 0, "DS: nothing to withdraw");
require(newDeposited_ >= pool.minimalStake || newDeposited_ == 0, "DS: invalid withdraw amount");

https://github.com/Cyfrin/2024-01-Morpheus/blob/76898177fbedcbbf4b78b513d9fa151bbf3388de/contracts/Distribution.sol#L255C1-L258C110

If the contract's balance is less than the minimal stake, users with staked amounts that would result in a remaining balance below the minimal stake (but not zero) after withdrawal are prevented from withdrawing any funds.

Steps to Reproduce

  1. User stakes an amount greater than the minimal stake in a public pool.

  2. The contract's balance of depositToken decreases due to other users' withdrawals or other actions, falling below the minimal stake amount.

  3. The user attempts to withdraw a portion of their stake, which would result in a remaining staked amount below the minimal stake but greater than zero.

  4. The withdrawal transaction fails due to the require statement enforcing the minimal stake rule.

Impact

Users with stakes above the minimal stake amount but below the contract's balance could find their funds locked in the contract if the contract's balance drops below the minimal stake threshold. This could occur in scenarios where there are many partial withdrawals, leading to a reduced contract balance, or if there is a discrepancy between the tokens owed to users and the actual tokens held by the contract.

Tools Used

Manual Review

Recommendations

To address this issue, the withdrawal logic should be updated to allow users to withdraw their funds even if the contract's balance falls below the minimal stake amount.

Specifically, the require statement that enforces the minimal stake rule should be modified to permit withdrawals up to the available balance of the contract. This change would ensure that users are not left with their funds locked in the contract due to balance constraints.

The updated require statement could be as follows:

// Allow withdrawal if the new deposited amount is zero, or if it's below the minimal stake but the contract's balance is also below the minimal stake
require(
newDeposited_ >= pool.minimalStake ||
newDeposited_ == 0 ||
(depositTokenContractBalance_ < pool.minimalStake && newDeposited_ <= depositTokenContractBalance_),
"DS: invalid withdraw amount"
);

The user can withdraw their balance once additional funds are deposited into the contract.

Updates

Lead Judging Commences

inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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