Core Contracts

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

Failure to update the currentBuffer in `LendingPool::_withdrawFromVault` results in DOS risk to protocol.

Vulnerability Details

The LendingPool aims to maintain a liquidity buffer by rebalancing funds between the buffer (asset balance of RToken) and CurveVault. When a shortage occurs; asset balance of RToken < reserve.totalLiquidity, LendingPool::_rebalanceLiquidity calculates the shortfall and calls _withdrawFromVault to withdraw this amount from CurveVault,

uint256 desiredBuffer = totalDeposits.percentMul(liquidityBufferRatio);
uint256 currentBuffer = IERC20(reserve.reserveAssetAddress).balanceOf(reserve.reserveRTokenAddress);
if (currentBuffer > desiredBuffer) {
uint256 excess = currentBuffer - desiredBuffer;
// Deposit excess into the Curve vault
_depositIntoVault(excess);
} else if (currentBuffer < desiredBuffer) {
uint256 shortage = desiredBuffer - currentBuffer;
// Withdraw shortage from the Curve vault
@> _withdrawFromVault(shortage);
}

However, it does not transfer the withdrawn assets back to RToken, leaving the currentBuffer; the reserve asset balance in RToken - unchanged.

function _withdrawFromVault(uint256 amount) internal {
// @audit withdrawn amount not transferred back?
@> curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));
totalVaultDeposits -= amount;
}

This failure to transfer creates a persistent liquidity shortage. Each subsequent call to _rebalanceLiquidity, triggered by user operations such as deposit, withdraw or borrow, detects the same unresolved shortage and attempts to withdraw the shortage from the CurveVault again. The repetitive withdrawls deplete the Vault's liquidity, and once exhausted, a revert would happen (e.g., reverting due to insufficient funds), causing _rebalanceLiquidity to revert.

Even if the Vault isn't totally exhausted, _withdrawFromVault would still revert due to underflow from amount being greater than totalVaultDeposits when repetitive withdrawals occur,

curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));
@> totalVaultDeposits -= amount;

Since _rebalanceLiquidity is integral to deposits, withdrawals and potential borrows which call ensureLiquidity to cover shortage, this failure results in a DoS, blocking users from interacting with the protocol.

The liquidity won't be trapped in the protocol since the owner can always call LendingPool::rescueToken to send tokens over to RToken, but that's a manual process, and during cases of high traffic, a DoS is bound to happen.

Impact

Users interacting with protocol would repeatedly face DoS, and the protocol would be unable to function properly.

Tools Used

Manual Review

Recommendations

Transfer the withdrawn assets back to RToken to update the currentBuffer and prevent the DoS.

function _withdrawFromVault(uint256 amount) internal {
curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));
+ IERC20(reserve.reserveAssetAddress).safeTransfer(reserve.reserveRTokenAddress, amount);
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!