Core Contracts

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

Curve Vault Deposit will fail due to Insufficient Token Balance

Summary

The LendingPool attempts to deposit reserve assets into Curve once it is above a particular threshold, _depositIntoVault
function assumes that the reserve assets are held by the lending pool contract when attempting to deposit into Curve. However, the assets are actually held by RToken. This misalignment causes deposit attempts to fail, effectively breaking core protocol functionality.

Vulnerability Details

The _rebalanceLiquidity function correctly checks the balance in the RToken contract and calls _depositIntoVaultif the current balance is greater than the desired balance.

function _rebalanceLiquidity() internal {
.....
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);
}
.....
}

However, _depositIntoVault attempts to:

  • Approve spending from the lending pool contract

  • Deposit tokens from the lending pool contract

    function _depositIntoVault(uint256 amount) internal {
    IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
    curveVault.deposit(amount, address(this));
    totalVaultDeposits += amount;
    }
  • The deposit transactions will always fail as Curve Vault will attempt to transfer the deposited tokens from the msg.sender

    def deposit(assets: uint256, receiver: address = msg.sender) -> uint256:
    ...
    assert self.borrowed_token.transferFrom(msg.sender, controller.address, assets, default_return_value=True)
    self._mint(receiver, to_mint)
    ...

Here is an implementation of the deposit function from Curve Vault docs.

Impact

All deposits to Curve vault will fail

  • Protocol cannot optimize yield through Curve strategy

  • Key functions (deposit, withdraw, borrow) will revert when attempting to rebalance once Curve vault is set

Tools Used

Manual code review

Recommendations

The lending pool should first withdraw from RTokenbefore depositing to Curve

function _depositIntoVault(uint256 amount) internal {
// withdraw from RToken
rToken.transferAsset(address(this), amount)
IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
curveVault.deposit(amount, address(this));
totalVaultDeposits += amount;
}
Updates

Lead Judging Commences

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