protocol-v2 icon indicating copy to clipboard operation
protocol-v2 copied to clipboard

Borrow: SafeMath: subtraction overflow

Open bugbuilder opened this issue 3 years ago • 3 comments

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.

bugbuilder avatar Jul 29 '21 06:07 bugbuilder

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"
        }
      ]
    }
  ]
}

bugbuilder avatar Jul 30 '21 11:07 bugbuilder

This can be handled inside the interest rate strategy calculcateInterestRates() method where availableLiquidity and liquidityTaken are available to compare

vminkov avatar Sep 24 '21 16:09 vminkov

Yep, that's true @vminkov, but imho we need to use the actual single responsibility principle used by ValidationLogic

bugbuilder avatar Sep 25 '21 00:09 bugbuilder