Core Contracts

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

LendingPool: Dos `_rebalanceLiquidity()` i.e deposit/withdraw function when crvVault is set, as RTokens hold crvUSD and not LendingPool

Summary

LendingPool manages all withdrawals and deposits of crvUSD. An extra feature exists, that will automatically stack crvUSD into curveVault to earn some extra yields.

When a user deposit crvUSD using LendingPool::deposit(), all crvUSD are sent to the RToken contract.

When curveVault != address(0) is active, the contract will _rebalanceLiquidity() on deposit and withdraw, in order to keep 20% on RToken and the rest in the curveVault

Vulnerability Details

The _depositIntoVault() function will never work when curveVault is set :

function _depositIntoVault(uint256 amount) internal {
IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount); //LendingPool approves curveVault as spender for crvUSD, but it holds nothings
curveVault.deposit(amount, address(this)); //this will always revert as LendingPool has no crvUSD. All deposit/withdraw functions failed when crvVault is set. Tokens are held by RTokenAddress, and not LendingPool, so all deposit/withdraw will fail, locking all NFT. It's impossible to reset this value
totalVaultDeposits += amount;
}

The function _depositIntoVault() will always revert, as it will try when calling curveVault.deposit(amount, address(this)) to transfer crvUSD from LendingPool to curveVault

And once curveVault is set, it's impossible to reset the value to address(0) to avoid triggering _rebalanceLiquidity(). _ensureLiquidity() is also affected

  1. protocol launch the pool

  2. users starts to use the LendingPool, depositing NFT/crvUSD and borrowing

  3. Protocol call setCurveVault(address(curveVault))

  4. All function using _rebalanceLiquidity() -> deposit(), withdraw(), borrow() are DoS.

  5. currentBuffer will be all crvUSD already on RToken, so probably a lot. There is a high chance that _updateLiquidity() will trigger this path. LendingPool will always try to deposit to curve vault and will revert.

Impact

After adding curveVault address, the LendingPool will be bricked, and users will not be able to deposit(), withdraw(), and borrow(). crvUSD amount in the contract will be stuck forever as it's not possible to reset curveVault to 0, and all deposited crvUSD in curveVault will be stuck too, as it will be impossible to withdraw() them.

Tools Used

Manual

Recommendations

Change the function so that it's RToken that deposit into the curve Vault :

LendingPool
function _depositIntoVault(uint256 amount) internal {
IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
+ rtoken.depositIntoVault(amount)
- curveVault.deposit(amount, address(this));
totalVaultDeposits += amount;
}
RToken
+ function depositIntoVault(uint256 amount) external onlyStabilityPool {
+ curveVault.deposit(amount, address(this));
+ }
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.