Core Contracts

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

Incorrect Withdrawal Logic in _withdrawFromVault

Summary

The _withdrawFromVault function in the contract incorrectly attempts to withdraw assets from the user (msg.sender) . Additionally, it sends the withdrawn assets to the lending pool instead of the RToken address. This flaw prevents users from borrowing or withdrawing assets when the protocol needs to replenish liquidity from the Curve vault. Furthermore, the incorrect withdrawal logic could result in users losing funds they are not supposed to pay, as the function attempts to withdraw assets from users instead of using protocol-controlled funds. The correct implementation should withdraw assets from the Curve vault, with the owner as the LendingPool (or RToken, based on protocol choice), and send them to the RToken address to ensure proper liquidity management.

Vulnerability Details

The _ensureLiquidity function checks the asset balance in the RToken address and attempts to withdraw from the Curve vault if there is insufficient liquidity. However, due to the incorrect withdrawal logic, the function fails to replenish liquidity, causing borrowing and withdrawal operations to revert. The _rebalanceLiquidity function also attempts to maintain the desired liquidity buffer by depositing or withdrawing assets from the Curve vault.

The _withdrawFromVault function attempts to withdraw assets from the user (msg.sender) and send them to the lending pool (address(this)). This is incorrect because the shares should be burned from LendingPool or another address where vault shares are controlled. And since lending and borrowing reserve assets are handlet at rToken contract withdraw reciever should be rToken contract.

/**
* @notice Internal function to withdraw liquidity from the Curve vault
* @param amount The amount to withdraw
*/
function _withdrawFromVault(uint256 amount) internal {
//@audit wrong owner and reciever
curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));
totalVaultDeposits -= amount;
}
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);
}

Impact

Users cannot borrow or withdraw assets when the protocol needs to replenish liquidity from the Curve vault.

Tools Used

Manual

Recommendations

Update withdraw paramaters and set reciever =reserveRTokenAddress , owner= LendingPool

function _withdrawFromVault(uint256 amount) internal {
// Withdraw assets from the Curve vault and send them to the RToken address
curveVault.withdraw(amount, reserve.reserveRTokenAddress, address(this), 0, new address[](0));
totalVaultDeposits -= amount;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month 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 about 1 month 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.