Core Contracts

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

A flaw in LendingPool::_withdrawFromVault() allows users to lose curveVault shares or to be DOSed when they call withdraw() or borrow() and there is not enough liquidity in the LendingPool

Summary

users are DOSed from withdrawing and borrowers or lose curveVault shares when there is not enough liquidity in the LendingPool due to a flaw in the LendingPool::_withdrawFromVault function.

Vunerability Details

When withdrawing funds or borrowing assets to users, the pool ensure if there enough liquidity available to perform the operation. The LendingPool::_ensureLiquidity function verifies it and pull funds from the curve Vault if needed using the LendingPool::_withdrawFromVault function.

File: https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/pools/LendingPool/LendingPool.sol#L754-L767
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) { // @audit If there is not enough liquidity to perform the operation
uint256 requiredAmount = amount - availableLiquidity;
// Withdraw required amount from the Curve vault
_withdrawFromVault(requiredAmount);
}
}
File: https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/pools/LendingPool/LendingPool.sol#L809-L812
function _withdrawFromVault(uint256 amount) internal {
// @audit receiver is *msg.sender* which is the caller of the external function that invokes _ensureLiquidity (withdraw or borrow)
curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));
totalVaultDeposits -= amount;
}

The issue is that the LendingPool::_withdrawFromVault function set msg.sender (the user) as the owner of the curveVault shares to be use to pull assets from the curve vault.

Impact

The results can be two-fold:

  • If the user does have curveVault shares and has approve the LendingPool to spend them, his shares are used to pay for part of the assets he receives. The amount of his shares corresponding to the amount of assets to withdraw from curveVault is burned and the assets is sent to the LendingPool.

  • If the user doesn't have curveVault shares anymore, the transaction reverts.

Tools Used

Manual review.

Recommendations

Change the owner to address(this) in the call to curveVault.withdraw function.

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

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

LendingPool::_withdrawFromVault incorrectly uses msg.sender instead of address(this) as the owner parameter, causing vault withdrawals to fail

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

LendingPool::_withdrawFromVault incorrectly uses msg.sender instead of address(this) as the owner parameter, causing vault withdrawals to fail

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.