Core Contracts

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

Incorrect token handling when receiving collateral from the curve vault

Summary

When rebalancing the Lending Pool liquidity, if more collateral is required, it is requested to be withdrawn from the Curve vault. However, the collateral received is stored directly in the Lending Pool contract instead of in the Rtoken one, breaking the protocol logic as it is not consistent with the overall system's collateral routing.

Vulnerability Details

LendingPool::rebalanceLiquidity function is called after a deposit or withdrawal of collateral token in order to rebalance the system liquidity. When this function determines that there is collateral shortage, _withdrawFromVault function is called. As a general rule, collateral token is held in the RToken contract, nevertheless, the received amount from the vault is stored in the Lending Pool contract instead. This discrepancy compromises the system consistency causing further processes to fail as liquidity is not correctly rebalanced.

> LendingPool.sol
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);
// @audit - collateral balance of RToken contact is the one checked to determine if liquidity rebalancing is needed
@> 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) {
uint256 shortage = desiredBuffer - currentBuffer;
// Withdraw shortage from the Curve vault
@> _withdrawFromVault(shortage);
}
emit LiquidityRebalanced(currentBuffer, totalVaultDeposits);
}
> LendingPool.sol
function _withdrawFromVault(uint256 amount) internal {
// @audit - receiver of the funds is this Lending Pool contract
@> curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));
totalVaultDeposits -= amount;
}

Impact

Impact: High

Likelihood: Medium

Tools Used

Manual Review

Recommendations

Add the corresponding logic to send to the RToken contract the collateral received from the vault.

> LendingPool.sol
function _withdrawFromVault(uint256 amount) internal {
curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));
+ IERC20(reserve.reserveAssetAddress).safeTransfer(
+ reserve.reserveRTokenAddress, // To
+ amount // amount
+ );
totalVaultDeposits -= amount;
}
Updates

Lead Judging Commences

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

Give us feedback!