Summary
LendingPool._rebalanceLiquidity()
rebalances liquidity between the buffer and the Curve vault to maintain the desired buffer ratio. However, it doesn't work correctly in case of currentBuffer
is larger than desiredBuffer
.
Vulnerability Details
When currentBuffer > desiredBuffer
, pool deposits excess into the Curve vault.
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);
} else if (currentBuffer < desiredBuffer) {
uint256 shortage = desiredBuffer - currentBuffer;
_withdrawFromVault(shortage);
}
emit LiquidityRebalanced(currentBuffer, totalVaultDeposits);
}
However, the pool doesn't hold any assets and RToken holds all deposited assets. Therefore, following function will revert and the pool can't deposit excess into Curve vault.
function _depositIntoVault(uint256 amount) internal {
@> IERC20(reserve.reserveAssetAddress).approve(address(curveVault), amount);
curveVault.deposit(amount, address(this));
totalVaultDeposits += amount;
}
We can check deposited assets sent to RToken in following code:
function deposit(ReserveData storage reserve,ReserveRateData storage rateData,uint256 amount,address depositor) internal returns (uint256 amountMinted) {
if (amount < 1) revert InvalidAmount();
updateReserveInterests(reserve, rateData);
>> IERC20(reserve.reserveAssetAddress).safeTransferFrom(
msg.sender,
>> reserve.reserveRTokenAddress,
amount
);
...
}
Impact
The pool can't deposit excess assets in the Curve vault.
Tools Used
Manual Review
Recommendations
Implement the mechanism which transfers the assets from the RToken to the Curve vault and update _rebalanceLiquidity()
.