Core Contracts

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

Insufficient `reserveAsset` balance of `LendingPool` results in DOS.

Vulnerability Details

The LendingPool::_rebalanceLiquidity attempts to maintain the desired buffer ratio by depositing to or withdrawing from the CurveVault. The implementation has a critical problem in _depositIntoVault which gets triggered when there's excess liquidity. It gives approval to the CurveVault to transfer excess amount of tokens, but fails to account for the fact that all the reserveAsset tokens are held by RToken contract. Whenever liquidity providers deposit, LendingPool keeps none of it; all of it is transferred to RToken.

// ReserveLibrary::deposit
function deposit(ReserveData storage reserve,ReserveRateData storage rateData,uint256 amount,address depositor) internal returns (uint256 amountMinted) {
if (amount < 1) revert InvalidAmount();
// Update reserve interests
updateReserveInterests(reserve, rateData);
// Transfer asset from caller to the RToken contract
@> IERC20(reserve.reserveAssetAddress).safeTransferFrom(
msg.sender, // from
reserve.reserveRTokenAddress, // to
amount // amount
);
...
...
}

When the CurveVault is given approval, and it tries to transfer the excess amount, it would fail because LendingPool doesn't have any of the reserveAsset since excess amount of reserveAsset tokens weren't transferred to the LendingPool before triggering the CurveVault::deposit.

function _depositIntoVault(uint256 amount) internal {
IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
@> curveVault.deposit(amount, address(this));
totalVaultDeposits += amount;
}

This results in DOS in following functions that make use of _rebalanceLiquidity,

  1. deposit

  2. withdraw

  3. borrow

Impact

A DOS in core functions severely impacts the protocol's core functionality.

Tools Used

Manual Review

Recommendations

Transfer tokens first before calling CurveVault::deposit

function _depositIntoVault(uint256 amount) internal {
+ IRToken(reserve.reserveRTokenAddress).rescueToken(reserve.reserveAssetAddress, address(this), amount);
IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
curveVault.deposit(amount, address(this));
totalVaultDeposits += amount;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 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 4 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.