Core Contracts

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

A flaw in the curve vault integration leads to DoS of the protocol's supply functionality

Summary

When users deposit assets, _depositIntoVault transfers crvusd to CurveVault on behalf of LendingPool. However, the contract does not transfer crvusd from the reserve address to LendingPool before calling CurveVault::deposit. As a result, _depositIntoVault attempts to deposit crvusd that LendingPool does not actually own (the assets are stored in reserve.reserveRTokenAddress), causing the CurveVault::deposit to fail or lead to unintended behavior.

Vulnerability Details

LendingPool::_rebalanceLiquidity is called upon supplying assets into the lending pool:

function _rebalanceLiquidity() internal {
// if curve vault is not set, do nothing
if (address(curveVault) == address(0)) {
return;
}
uint256 totalDeposits = reserve.totalLiquidity; // Total liquidity in the system
uint256 desiredBuffer = totalDeposits.percentMul(liquidityBufferRatio);
@> uint256 currentBuffer = IERC20(reserve.reserveAssetAddress).balanceOf(reserve.reserveRTokenAddress);
if (currentBuffer > desiredBuffer) {
@> uint256 excess = currentBuffer - desiredBuffer;
// Deposit excess into the Curve vault
@> _depositIntoVault(excess);
} else if (currentBuffer < desiredBuffer) {
...SKIP...
}
}

When the desiredBuffer cap is reached the depositIntoVault is called to deposit assets into CurveVault:

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

The issue arises because LendingPool does not transfer the necessary assets from reserve.reserveRTokenAddress to itself before approving and depositing it. As a result the LendingPool lacks sufficient asset amount, the deposit will fail, causing DoS of the supply functionality.

If we look at the CurveVault implementation, the assets are transferred from msg.sender (LendingPool).

Impact

Denial of Service: Deposits into CurveVault may fail, preventing new deposits from being processed.

Tools Used

Manual Research, VSCode

Recommendations

Ensure that crvusd is transferred from the reserve address to LendingPool before approving and depositing:

function _depositIntoVault(uint256 amount) internal {
+ IERC20(reserve.reserveAssetAddress).safeTransferFrom(reserve.reserveRTokenAddress, 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.