Core Contracts

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

Buffer withdrawn to wrong address in `_rebalanceLiquidity`

Summary

The _rebalanceLiquidity and _ensureLiquidity functions incorrectly withdraw tokens to the LendingPool address instead of the reserveRTokenAddress when rebalancing the buffer or ensuring liquidity, leading to potential accounting errors and redundant withdrawals.

Vulnerability Details

The issue occurs in the _rebalanceLiquidity function when currentBuffer < desiredBuffer:

else if (currentBuffer < desiredBuffer) {
uint256 shortage = desiredBuffer - currentBuffer;
// Withdraw shortage from the Curve vault
@> _withdrawFromVault(shortage);
}

And in _ensureLiquidity if (availableLiquidity < amount):

if (availableLiquidity < amount) {
uint256 requiredAmount = amount - availableLiquidity;
// Withdraw required amount from the Curve vault
@> _withdrawFromVault(requiredAmount);
}

The _withdrawFromVault function withdraws the shortage / requiredAmount from the Curve vault and transfers it to the LendingPool address:

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

Tokens are withdrawn to LendingPool address instead of reserveRTokenAddress
currentBuffer and availableLiquidity check balance at reserveRTokenAddress but withdrawals don't go there
This mismatch means subsequent calls will keep detecting a shortage
Results in repeated withdrawals since withdrawals never increases at reserveRTokenAddress

Impact

  • Buffer mechanism becomes ineffective as tokens aren't stored in correct location

  • Repeated unnecessary withdrawals from vault on each rebalance and ensureLiquidity call

  • Increased gas costs from redundant operations

  • Potential depletion of vault liquidity through repeated withdrawals

  • Break in system invariants around buffer and liquidity maintenance

Tools Used

Manual review

Recommendations

  • Modify _withdrawFromVault to withdraw to reserveRTokenAddress:

function _withdrawFromVault(uint256 amount) internal {
// Change withdrawal destination to reserveRTokenAddress
curveVault.withdraw(amount, reserve.reserveRTokenAddress);
}
  • Add validation to ensure tokens arrive at correct address:

function _withdrawFromVault(uint256 amount) internal {
uint256 balanceBefore = IERC20(reserve.reserveAssetAddress).balanceOf(reserve.reserveRTokenAddress);
curveVault.withdraw(amount, reserve.reserveRTokenAddress);
uint256 balanceAfter = IERC20(reserve.reserveAssetAddress).balanceOf(reserve.reserveRTokenAddress);
require(balanceAfter - balanceBefore == amount, "Withdrawal failed");
}
Updates

Lead Judging Commences

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