Core Contracts

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

Incorrect asset source when depositing when rebalancing the liquidity causes DoS in LendingPool

Summary

The LendingPool's liquidity rebalancing mechanism incorrectly assumes the excess crvUSD buffer is held in the LendingPool contract when it's actually held in the RToken contract. This mismatch causes the _depositIntoVault function to fail due to insufficient balance, resulting in a DoS of core protocol functions that depend on liquidity rebalancing.

Vulnerability Details

The issue stems from a fundamental misunderstanding in how asset custody works in the protocol. Let's break down the flow:

When users deposit crvUSD into the protocol, the assets are transferred to the RToken contract, not the LendingPool:

When deposit() is called on the LendingPool the ReserveLibrary's deposit() function is used internally,

// In ReserveLibrary.deposit():
IERC20(reserve.reserveAssetAddress).safeTransferFrom(
msg.sender, // from
reserve.reserveRTokenAddress, // to -> RToken gets the assets
amount
);

The _rebalanceLiquidity function checks balances and attempts to rebalance:

function _rebalanceLiquidity() internal {
uint256 totalDeposits = reserve.totalLiquidity;
uint256 desiredBuffer = totalDeposits.percentMul(liquidityBufferRatio);
// @audit HERE IS THE ISSUE - checking RToken's balance but LendingPool will try to spend it
uint256 currentBuffer = IERC20(reserve.reserveAssetAddress).balanceOf(reserve.reserveRTokenAddress);
if (currentBuffer > desiredBuffer) {
uint256 excess = currentBuffer - desiredBuffer;
_depositIntoVault(excess); // @audit Will fail as LendingPool doesn't have these tokens
}
//...
}

When attempting to deposit to the vault:

function _depositIntoVault(uint256 amount) internal {
// @audit This will fail as LendingPool contract doesn't have the tokens
IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
curveVault.deposit(amount, address(this));
totalVaultDeposits += amount;
}

The failure in _depositIntoVault causes _rebalanceLiquidity to revert, which is called in critical functions:

function deposit(uint256 amount) external ... {
//...
_rebalanceLiquidity(); // @audit Will revert
}
function withdraw(uint256 amount) external ... {
//...
_rebalanceLiquidity(); // @audit Will revert
}
function borrow(uint256 amount) external ... {
//...
_rebalanceLiquidity(); // @audit Will revert
}

PoC

  1. Alice deposits 1000 crvUSD into the protocol

  2. The crvUSD tokens are transferred to the RToken contract

  3. The protocol calculates desiredBuffer as 200 crvUSD (20% of 1000)

  4. Since currentBuffer (1000 in RToken) > desiredBuffer (200)

  5. LendingPool tries to deposit 800 crvUSD to Curve vault

  6. Transaction reverts as LendingPool has 0 crvUSD

Impact

  • Complete DoS of core protocol functions (deposit, withdraw, borrow) due to failed liquidity rebalancing.

  • The excess crvUSD is never deposited in to the curve vault

Tools Used

Manual review

Recommendations

Modify _depositIntoVault to first transfer the assets from RToken to LendingPool:

function _depositIntoVault(uint256 amount) internal {
// First transfer from RToken to LendingPool
IRToken(reserve.reserveRTokenAddress).transferAsset(address(this), amount);
// Then proceed with vault deposit
IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
curveVault.deposit(amount, address(this));
totalVaultDeposits += amount;
}
Updates

Lead Judging Commences

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

LendingPool::_depositIntoVault and _withdrawFromVault don't transfer tokens between RToken and LendingPool, breaking Curve vault interactions

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

LendingPool::_depositIntoVault and _withdrawFromVault don't transfer tokens between RToken and LendingPool, breaking Curve vault interactions

Support

FAQs

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