Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Valid

Missing Slippage Protection in `LendingPool.deposit()`

Summary

The deposit() function in LendingPool lacks slippage protection, allowing an attacker to manipulate the liquidityIndex and reduce the amount of rToken minted for a user. This results in fewer reward tokens (raacToken) in the StabilityPool.

Vulnerability Details

In LendingPool.deposit(), when a user deposits X amount of crvUSD, they receive rToken based on the liquidityIndex. However, this value can be front-run by a malicious actor who increases utilization by borrowing the present crvUSD, thereby increasing liquidityIndex and reducing the user's expected rToken amount.

PoC

Affected Code

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/pools/LendingPool/LendingPool.sol#L225C5-L236C6

Since liquidityIndex can be manipulated before execution, the final rTokenAmount is uncertain.

  1. Assume liquidityIndex = 1e27 at the time of deposit.

  2. A user deposits 100 crvUSD into LendingPool.deposit(), expecting:

    rTokenAmount = (100 * 1e27) / 1e27 = 100 rToken;
  3. A malicious actor front-runs the deposit by borrowing crvUSD, increasing liquidityIndex due to the formula:

    liquidityIndex = previousLiquidityIndex * (1 + currentLiquidityRate)
  4. If liquidityIndex increases to 1.1e27, the user now gets:

    rTokenAmount = (100 * 1e27) / 1.1e2790.9 rToken;
  5. The user unknowingly receives fewer rToken, leading to a reduced amount of raacToken rewards in the StabilityPool.

Impact

  • Users receive fewer rToken than expected.

  • This results in lower deToken and raacToken rewards in StabilityPool.

  • The manipulation affects the fairness and predictability of the deposit process.

Tools Used

Manual Review

Recommendations

Implement slippage protection by requiring a minimum rToken output, either:

  1. Specifying an expected rToken amount in BPS (basis points).

  2. Allowing users to provide a minRTokenAmount parameter, reverting if not met:

- function deposit(uint256 amount) external nonReentrant whenNotPaused onlyValidAmount(amount) {
+ function deposit(uint256 amount, uint256 expected) external nonReentrant whenNotPaused onlyValidAmount(amount) {
ReserveLibrary.updateReserveState(reserve, rateData);
uint256 mintedAmount = ReserveLibrary.deposit(reserve, rateData, amount, msg.sender);
+ if (mintedAmount < expected) revert();
_rebalanceLiquidity();
emit Deposit(msg.sender, amount, mintedAmount);
}

This prevents deposits from being executed under manipulated conditions.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

LendingPool deposit/withdraw functions lack slippage protection

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

LendingPool deposit/withdraw functions lack slippage protection

Support

FAQs

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