protocol-v2
protocol-v2 copied to clipboard
Borrow: SafeMath: subtraction overflow
If someone tries to make a borrow that is bigger than the available liquidity, DefaultReserveInterestRateStrategy.calculateInterestRates it will throw a SafeMath exception.
We could fix this adding this code to ValidationLogic.validateBorrow:
DataTypes.ReserveData storage targetReserve = reservesData[vars.asset];
uint256 availableLiquidity = IERC20(vars.asset).balanceOf(targetReserve.aTokenAddress);
require(amount <= availableLiquidity, Errors.VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH);
but we've to keep in mind that this method is called from LendingPool.flashLoan, meaning that flashloan was called with an open debt and the underlying asset was already released, so we've to check this, one option could be to use the struct ExecuteBorrowParams and read the releaseUnderlying flag.
Because the floashloan released the underlying asset first, probably the maxLoanSizeStable for stable rates is not accurate and also needs to read the releaseUnderlying flag.
I'll be happy to code the fix but I need your feedback.
You can reproduce this error add this test case scenario
{
"title": "LendingPool: Borrow that is bigger than the available liquidity (reverts)",
"description": "Test cases for the borrow function.",
"stories": [
{
"description": "User 0 deposits 1000 DAI, user 1 deposits 1 WETH as collateral and tries to borrow 10000 DAI (revert expected)",
"actions": [
{
"name": "mint",
"args": {
"reserve": "DAI",
"amount": "1000",
"user": "0"
},
"expected": "success"
},
{
"name": "approve",
"args": {
"reserve": "DAI",
"user": "0"
},
"expected": "success"
},
{
"name": "deposit",
"args": {
"reserve": "DAI",
"amount": "1000",
"user": "0"
},
"expected": "success"
},
{
"name": "mint",
"args": {
"reserve": "WETH",
"amount": "1",
"user": "1"
},
"expected": "success"
},
{
"name": "approve",
"args": {
"reserve": "WETH",
"user": "1"
},
"expected": "success"
},
{
"name": "deposit",
"args": {
"reserve": "WETH",
"amount": "1",
"user": "1"
},
"expected": "success"
},
{
"name": "borrow",
"args": {
"reserve": "DAI",
"amount": "10000",
"borrowRateMode": "variable",
"user": "1"
},
"expected": "revert",
"revertMessage": "Current availbe liquidity not enough"
}
]
}
]
}
This can be handled inside the interest rate strategy calculcateInterestRates() method where availableLiquidity
and liquidityTaken
are available to compare
Yep, that's true @vminkov, but imho we need to use the actual single responsibility principle used by ValidationLogic