Core Contracts

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

Incorrect Reserve Token Custody in Excess Deposits

Summary

A vulnerability exists in the _rebalanceLiquidity() function of the LendingPool contract, where it incorrectly assumes that excess reserve tokens are already in the custody of LendingPool. However, all reserve tokens are held in RToken.sol. This discrepancy leads to deposit(), withdraw() and borrow() reverts, in addition to preventing excess funds from being deposited into the Curve Vault to generate additional yield.

Vulnerability Details

The _rebalanceLiquidity() function is designed to deposit excess reserve tokens into the Curve Vault when the buffer exceeds the desired level:

LendingPool.sol#L778-L785

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);

The problem arises because currentBuffer refers to reserve tokens held by RToken.sol, not directly by LendingPool. However, the function assumes that the excess tokens are already available for immediate deposit.

In the current implementation:

LendingPool.sol#L799-L803

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

Since LendingPool does not have custody of the excess reserve tokens, this results in failed deposits and potentially reverts during liquidity rebalancing.

Impact

  1. Failed Excess Token Deposits: Excess reserve tokens remain idle in RToken.sol instead of being deposited into the Curve Vault, preventing the protocol from earning yield on those assets.

  2. Inefficient Capital Utilization: Protocol on behalf of users lose out on potential yield generation, leading to long-term inefficiencies in the protocol’s performance.

  3. Reverts in Deposit, Withdraw and Borrow Functions: The _rebalanceLiquidity() function is embedded within LendingPool.deposit(), LendingPool.withdraw() and LendingPool.borrow(). If the excess token transfer logic fails, these calls could revert, directly affecting user operations and leading to potential denial of service for lending/liquidity management.

Tools Used

Manual

Recommendations

Consider making the following refactoring:

LendingPool.sol#L782-L785

if (currentBuffer > desiredBuffer) {
uint256 excess = currentBuffer - desiredBuffer;
+ // Transfer excess tokens from RToken.sol to LendingPool
+ IRToken(reserve.reserveRTokenAddress).transferAsset(address(this), excess);
// Deposit excess into the Curve vault
_depositIntoVault(excess);
Updates

Lead Judging Commences

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