The Lending Pool's liquidity rebalancing mechanism interacts with a Curve vault to optimize liquidity distribution. However, the _withdrawFromVault function in LendingPool hardcodes the max_loss parameter to 0, making the system vulnerable to denial-of-service (DOS) if the Curve vault ever incurs a small, unavoidable loss. This prevents users from withdrawing or depositing funds, disrupting core protocol functionality.
Users who want to gain RAAC tokens have to deposit crvUSD via LendingPool::deposit which mints Rtokens in return which are then deposited in the stability pool to gain RAAC token rewards. See LendingPool::deposit:
According to the documentation, users are allowed to withdraw assets they have deposited via LendingPool::withdraw at any time. See function:
LendingPool::deposit and LendingPool::withdraw both call LendingPool::_rebalanceLiquidity(). This function sets a liquidity buffer ratio which is what determines whether RAAC should deposit excess liquidity to a curve vault to get rewards or not. So it sets a buffer ratio and if the total available liquidity is greater than the buffer they should have, they deposit the excess into curve vault which is simply a crvUSD vault where users can deposit assets and gain rewards. if the total available liquidity is less than the buffer they should have, they withdraw the shortage from the curve vault. See function below:
The key DOS for deposits and withdrawals happens in LendingPool::_withdrawFromVault. See below:
The curve vault code can be viewed at . The curve vault contains a withdraw function written in vyper. On inspection of that function, it can be seen that where LendingPool::_withdrawFromVault passes 0 to the curve vault's withdraw function is a max_loss variable where the caller specifies the maximum amount of losses they are willing to take during the withdrawal. See the following extracts from the vault code:
There is also the following line in the _redeem function which is what handles the withdrawal:
Since the hardcoded value passed as max_loss is 0, if there is ever a situation where the vault strategy takes losses and needs to pass these losses on to the user, which is RAAC in this case, the transaction will simply revert with "too much loss". As a result, any function that calls LendingPool::_rebalanceLiquidity() will also revert which stops RAAC users from being able to perform key functionality. If the Curve vault’s strategy incurs even a tiny loss, no funds can be withdrawn, effectively halting the ability to deposit and withdraw funds in the Lending Pool.
I would write a POC for this but the curve vault is written in vyper and I would have to convert this to solidity which includes knowing what the curve default strategies are how to implement them which is time intensive and impractical when the issue is explainable in text.
Denial of Service (DOS) for Deposits & Withdrawals: Since _rebalanceLiquidity() is triggered in both deposit() and withdraw(), if _withdrawFromVault() keeps reverting, no users will be able to deposit or withdraw funds.
Liquidity Freeze: Funds that should be withdrawn from the Curve vault remain stuck, leaving the Lending Pool with an insufficient balance to process withdrawals.
Protocol Downtime: If the Curve vault operates normally but produces small losses, the Lending Pool will remain permanently broken unless manually fixed by governance.
Manual Review
To prevent this issue:
Make max_loss configurable: Introduce a function to update the maximum allowable loss dynamically.
Set a reasonable default max_loss: Instead of 0, consider allowing a small, configurable loss (e.g., 1e16 for 1%).
Fail Gracefully: If a withdrawal reverts due to loss, allow the protocol to adjust or retry with a higher max_loss.
Suggested Fix:
Modify _withdrawFromVault() to allow adjustable max_loss:
This ensures:
RAAC can withdraw funds even with minimal loss.
Governance can adjust maxLoss if needed.
Users are not indefinitely locked out of deposits/withdrawals.
By making maxLoss configurable, the protocol avoids system-wide failures while still ensuring losses remain minimal and controlled.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.