Core Contracts

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

The LendingPool.sol's `withdraw` and `borrow` function will always revert in case amount being > liquidity available in the reserves

Summary

When the withdraw and borrow functions are called, both of these have an internal function- _ensureLiquidity that is called to check or make sure if their is sufficeint liquidity in the reserves to cover the amount that is being asked by the user for borrowing or withdrawals and if there isnt enough liquidity present in the reserves, the required liquidity that is needed for the borrow or withdraw is taken out from the CurveVault. The issue here is that when the users call those function borrow or withdraw the amount that they ask for is transferred to them from the RToken contract but in the case of liquidity being insufficient in that reserve the _withdrawFromVault function calls the CrvVault's withdraw function and in the receiver param address(this) is passed in i.e is the LendingPool contract in this case, however it should be the RToken address that should get the required amount so that the borrow and withdrawal amount can be given out/transferred to the caller but since the RToken address never receives the required amount. The result of this will be that both the borrow and withdraw functions will revert after reaching last line of the functions i.e updateInterestRatesAndLiquidity and inside this function this line will hit and the whole transaction will revert due to this. Also Note that this vulnerability can also be exploited by a malicious user via front running as all he will have to do is front run the borrower's tx and call borrow with an amount that will make the liquidtiy in the reserve insuffcient and that will also include the user spending some gas money for no reason due to this exploitation

Vulnerability Details

function _ensureLiquidity(uint256 amount) internal {
// if curve vault is not set, do nothing
if (address(curveVault) == address(0)) {
return;
}
uint256 availableLiquidity = IERC20(reserve.reserveAssetAddress)
.balanceOf(reserve.reserveRTokenAddress);
if (availableLiquidity < amount) {
uint256 requiredAmount = amount - availableLiquidity;
// Withdraw required amount from the Curve vault
_withdrawFromVault(requiredAmount); //<-
}
}```
```function _withdrawFromVault(uint256 amount) internal {
curveVault.withdraw(
amount,
address(this), //AUDIT- This should be Reserve.(RTokenAddress) instead of this
msg.sender,
0,
new address[](0)
);```
``` function updateInterestRatesAndLiquidity(ReserveData storage reserve,ReserveRateData storage rateData,uint256 liquidityAdded,uint256 liquidityTaken) internal {
// Update total liquidity
if (liquidityAdded > 0) {
reserve.totalLiquidity = reserve.totalLiquidity + liquidityAdded.toUint128();
}
if (liquidityTaken > 0) {
//-> if (reserve.totalLiquidity < liquidityTaken) revert InsufficientLiquidity();
```
## Impact
The user will not be able to withdraw or borrow when the liquidity is not enough in the reserve, even if they are supposed to withdraw as the `_ensureLiquidity` function is there for that sole purpose i.e when their isnt enough liquidity in the reserve, the required amount of funds can be taken out from the Curve Vault.
## Tools Used
Manual Review
## Recommendations
When ensuring liquidity, and withdrawing funds from the vault, send them to the `RToken` address instead of `address(this)` which is the LendingPool contract here. For eg:
```
function _withdrawFromVault(uint256 amount) internal {
curveVault.withdraw(amount, (reserve.reserveRTokenAddress), (reserve.reserveRTokenAddress), 0, new address[](0));
totalVaultDeposits -= amount;
}
}```
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!