When a user borrows reserve assets via borrow()in LendingPool.sol, the source of these reserve assets is the Rtoken contract. However, when the _ensureLiquidity() function called within the borrow() function ensures there is sufficient liquidity to be able to lend to the borrower, the Curve Vault transfers the reserve assets to LendingPool.sol instead of the the RToken contract.
Looking at the flow of borrow()function in LendingPool.sol, assume this scenario:
Alice calls borrow() and wishes to borrow 100,000 crvUSD
Alice's collateral value is retrieved via getUserCollateralValue()
Reserve states are updated via ReserveLibrary.updateReserveState()
Function ensures there is sufficient liquidity via _ensureLiquidity()
Now, let's assume available liquidity in rToken address = 50,000 crvUSD
since availableLiquidity < 100_000e18, _withdrawFromVault()is called
amount (which is 50_000e18) is withdrawn from the Curve Vault to address(this), which is LendingPool.sol
Back to the borrow()function, function checks if Alice has sufficient collateral to cover her debt
DebtTokens are minted to Alice to represent her 100,000 crvUSD debt
Now, 100,000 crvUSD is transferred to Alice:
Rtoken.transferAsset()is called
100,000 crvUSD is being transferred from RToken address to Alice
This transfer will fail, because RToken address still has only 50,000 crvUSD. Alice will not get her borrowed 100,000 crvUSD
[_withdrawFromVault] (https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/pools/LendingPool/LendingPool.sol#L809-L812)
This misallocation of liquidity can result in severe disruptions in lending operations. LendingPool.sol will receive crvUSD from the Curve vault, but the available liquidity is measured by the balance of crvUSD in the RToken contract. This leads to excessive top-ups of crvUSD to LendingPool.sol, and yet user cannot borrow crvUSD due to insufficient reserve assets in RToken contract.
Manual
In _withdrawFromVault(), change the recipient of crvUSD from address(this)to reserve.reserveRTokenAddress.
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.