Core Contracts

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

Liquidity Rebalancing Fails to Restore Reserve Token Buffer

Summary

The _rebalanceLiquidity function is designed to maintain a liquidity buffer for the reserve token (RT). However, due to an incorrect withdrawal mechanism, when a shortage is detected, the withdrawn funds are sent to the LendingPool contract instead of the RT token contract. This means that the buffer remains unchanged, preventing effective rebalancing.

Vulnerability Details

Current Implementation of _rebalanceLiquidity
function _rebalanceLiquidity() internal {
if (address(curveVault) == address(0)) {
return;
}
uint256 totalDeposits = reserve.totalLiquidity;
uint256 desiredBuffer = totalDeposits.percentMul(liquidityBufferRatio);
uint256 currentBuffer = IERC20(reserve.reserveAssetAddress).balanceOf(reserve.reserveRTokenAddress);
if (currentBuffer > desiredBuffer) {
uint256 excess = currentBuffer - desiredBuffer;
_depositIntoVault(excess); // Depositing excess liquidity into Curve vault
} else if (currentBuffer < desiredBuffer) {
uint256 shortage = desiredBuffer - currentBuffer;
_withdrawFromVault(shortage); // Attempting to withdraw shortage
}
emit LiquidityRebalanced(currentBuffer, totalVaultDeposits);
}
Incorrect Implementation of _withdrawFromVault
function _withdrawFromVault(uint256 amount) internal {
curveVault.withdraw(amount, address(this), msg.sender, 0, new address totalVaultDeposits -= amount;
}
Key Issue
  • The function withdraws amount from the Curve vault to address(this), which is the LendingPool contract.

  • However, _rebalanceLiquidity expects this withdrawn amount to increase the balance of RT token contract (reserve.reserveRTokenAddress).

  • Since the funds are not moved to the RT contract, the buffer level remains low despite the withdrawal, causing an infinite loop where liquidity shortages are never fixed.

Impact

  1. Liquidity Buffer Never Replenishes

    • Even when _rebalanceLiquidity withdraws funds, the buffer check will still detect a shortage because the RT contract balance does not increase.

  2. Repeated Withdrawals Without Fixing Issue

    • The function will keep withdrawing from Curve vault unnecessarily, wasting gas and potentially draining liquidity from the vault.

Recommended Fix

Modify _withdrawFromVault to ensure that the withdrawn amount is sent directly to the RT token contract (reserve.reserveRTokenAddress) instead of the LendingPool contract.

Fixed _withdrawFromVault Implementation
function _withdrawFromVault(uint256 amount) internal {
curveVault.withdraw(amount, reserve.reserveRTokenAddress, msg.sender, 0, new address ); totalVaultDeposits -= amount;
}
Additional Safeguard

After withdrawal, explicitly check whether the RT token balance increased as expected:

uint256 newBuffer = IERC20(reserve.reserveAssetAddress).balanceOf(reserve.reserveRTokenAddress);
require(newBuffer >= currentBuffer + amount, "Liquidity buffer not replenished");

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 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 4 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.