Core Contracts

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

Incorrect Liquidity Handling Causes Failed Withdrawals and Protocol Insolvency

Impact

https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/pools/LendingPool/LendingPool.sol#L772-L793
Users cannot withdraw funds even when the protocol has sufficient liquidity. The withdrawal process is fundamentally broken because liquidity intended to cover withdrawals is routed to the wrong contract (LendingPool instead of the RToken buffer). This results in:

  • Failed transactions for all withdrawals requiring vault top-ups.

  • Loss of user trust and potential fund lockup.


Proof of Concept

Affected Code

  1. Liquidity Check Misdirects Funds

    • _ensureLiquidity withdraws from the vault to address(this) (LendingPool) instead of reserveRTokenAddress.

    function _ensureLiquidity(uint256 amount) internal {
    ...
    _withdrawFromVault(requiredAmount); // Sends to LendingPool
    }
  2. Withdrawal Relies on Incorrect Buffer

    function withdraw(...) internal returns (...) {
    IRToken(reserve.reserveRTokenAddress).burn(...); // Pulls from RToken buffer
    }
  3. Rebalance Fails to Fix Buffer

    • _rebalanceLiquidity withdraws vault funds to address(this), not reserveRTokenAddress, leaving the buffer underfunded.

Vulnerability Flow

  1. User requests withdrawal of X tokens.

  2. reserveRTokenAddress has Y < X tokens.

  3. _ensureLiquidity withdraws X - Y tokens from the vault to LendingPool (not reserveRTokenAddress).

  4. ReserveLibrary.withdraw attempts to send X tokens from reserveRTokenAddress (still Y tokens), causing a revert.

  5. _rebalanceLiquidity is never executed (transaction already reverted).


Tools Used

  • Manual code review

Recommended Mitigation Steps

1. Fix Liquidity Routing

Modify _withdrawFromVault to send withdrawn funds to reserveRTokenAddress:

function _withdrawFromVault(uint256 amount) internal {
curveVault.withdraw(amount, reserve.reserveRTokenAddress, msg.sender, 0, new address[](0));
totalVaultDeposits -= amount;
}

2. Adjust Rebalancing Logic

Update _rebalanceLiquidity to interact with reserveRTokenAddress:

  • When depositing excess buffer liquidity into the vault, pull from reserveRTokenAddress.

  • When withdrawing to cover shortages, send funds to reserveRTokenAddress.

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!