Skip to content
This repository has been archived by the owner on Dec 17, 2023. It is now read-only.

volodya - AaveLeverageStrategyExtension doesn't work with turned on Efficiency Mode #5

Closed
sherlock-admin opened this issue Jun 14, 2023 · 1 comment
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label High A valid High severity issue Reward A payout will be made for this issue

Comments

@sherlock-admin
Copy link
Contributor

sherlock-admin commented Jun 14, 2023

volodya

medium

AaveLeverageStrategyExtension doesn't work with turned on Efficiency Mode

Summary

AaveLeverageStrategyExtension doesn't work with turned-on Efficiency Mode. Incorrect

  • LTV (Loan to value)
  • Liquidation threshold
  • Liquidation bonus
  • A custom price oracle (optional)

Vulnerability Detail

According to aave docs whenever a pool in eMode it does how its own

  • LTV (Loan to value)
  • Liquidation threshold
  • Liquidation bonus
  • A custom price oracle (optional)

Whenever pool in eMode these params are not being fetched but instead using the same params as if eMode is not on which leads to the system having unexpected issues.

You can see from Morpho protocol that they are using different ltv and other params if pool in eMode

 function _assetLiquidityData(address underlying, Types.LiquidityVars memory vars)
        internal
        view
        returns (uint256 underlyingPrice, uint256 ltv, uint256 liquidationThreshold, uint256 underlyingUnit)
    {
        DataTypes.ReserveConfigurationMap memory config = _pool.getConfiguration(underlying);

        bool isInEMode;
        (isInEMode, underlyingPrice, underlyingUnit) =
            _assetData(underlying, vars.oracle, config, vars.eModeCategory.priceSource);

        // If the LTV is 0 on Aave V3, the asset cannot be used as collateral to borrow upon a breaking withdraw.
        // In response, Morpho disables the asset as collateral and sets its liquidation threshold
        // to 0 and the governance should warn users to repay their debt.
        if (config.getLtv() == 0) return (underlyingPrice, 0, 0, underlyingUnit);

        if (isInEMode) {
            ltv = vars.eModeCategory.ltv;
            liquidationThreshold = vars.eModeCategory.liquidationThreshold;
        } else {
            ltv = config.getLtv();
            liquidationThreshold = config.getLiquidationThreshold();
        }
    }

src/MorphoInternal.sol#L322

However, in Index eMode is not being used to determine ltv, liquidationThreshold and other params

    function _calculateMaxBorrowCollateral(ActionInfo memory _actionInfo, bool _isLever) internal view returns(uint256) {
        
        // Retrieve collateral factor and liquidation threshold for the collateral asset in precise units (1e16 = 1%)
        ( , uint256 maxLtvRaw, uint256 liquidationThresholdRaw, , , , , , ,) = strategy.aaveProtocolDataProvider.getReserveConfigurationData(address(strategy.collateralAsset));

        // Normalize LTV and liquidation threshold to precise units. LTV is measured in 4 decimals in Aave which is why we must multiply by 1e14
        // for example ETH has an LTV value of 8000 which represents 80%
        if (_isLever) {
            uint256 netBorrowLimit = _actionInfo.collateralValue
                .preciseMul(maxLtvRaw.mul(10 ** 14))
                .preciseMul(PreciseUnitMath.preciseUnit().sub(execution.unutilizedLeveragePercentage));

            return netBorrowLimit
                .sub(_actionInfo.borrowValue)
                .preciseDiv(_actionInfo.collateralPrice);
        } else {
            uint256 netRepayLimit = _actionInfo.collateralValue
                .preciseMul(liquidationThresholdRaw.mul(10 ** 14))
                .preciseMul(PreciseUnitMath.preciseUnit().sub(execution.unutilizedLeveragePercentage));

            return _actionInfo.collateralBalance
                .preciseMul(netRepayLimit.sub(_actionInfo.borrowValue))
                .preciseDiv(netRepayLimit);
        }
    }

adapters/AaveLeverageStrategyExtension.sol#L1095

Impact

System will not work properly in eMode

Code Snippet

Tool used

Manual Review

Recommendation

First, add global eModCategoryId variable which will be 0 by default

    function setEModeCategory(uint8 _categoryId) external onlyOperator {
+        eModCategoryId = _categoryId;
        _setEModeCategory(_categoryId);
    }

fetch data from eMode if its not 0, also do the same for oracle, like Morho is doing

    function _calculateMaxBorrowCollateral(ActionInfo memory _actionInfo, bool _isLever) internal view returns(uint256) {
        
        // Retrieve collateral factor and liquidation threshold for the collateral asset in precise units (1e16 = 1%)
        ( , uint256 maxLtvRaw, uint256 liquidationThresholdRaw, , , , , , ,) = strategy.aaveProtocolDataProvider.getReserveConfigurationData(address(strategy.collateralAsset));

+        if (eModCategoryId > 0) {
+            eModeCategory = _pool.getEModeCategoryData(eModCategoryId);
+            maxLtvRaw = eModeCategory.ltv;
+            liquidationThreshold = eModeCategory.liquidationThreshold;
+        }

        // Normalize LTV and liquidation threshold to precise units. LTV is measured in 4 decimals in Aave which is why we must multiply by 1e14
        // for example ETH has an LTV value of 8000 which represents 80%
        if (_isLever) {
            uint256 netBorrowLimit = _actionInfo.collateralValue
                .preciseMul(maxLtvRaw.mul(10 ** 14))
                .preciseMul(PreciseUnitMath.preciseUnit().sub(execution.unutilizedLeveragePercentage));

            return netBorrowLimit
                .sub(_actionInfo.borrowValue)
                .preciseDiv(_actionInfo.collateralPrice);
        } else {
            uint256 netRepayLimit = _actionInfo.collateralValue
                .preciseMul(liquidationThresholdRaw.mul(10 ** 14))
                .preciseMul(PreciseUnitMath.preciseUnit().sub(execution.unutilizedLeveragePercentage));

            return _actionInfo.collateralBalance
                .preciseMul(netRepayLimit.sub(_actionInfo.borrowValue))
                .preciseDiv(netRepayLimit);
        }
    }

Duplicate of #251

@github-actions github-actions bot added the Excluded Excluded by the judge without consulting the protocol or the senior label Jun 19, 2023
@IAm0x52
Copy link
Collaborator

IAm0x52 commented Jun 22, 2023

Dupe of #251

@0xffff11 0xffff11 added High A valid High severity issue Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label and removed Excluded Excluded by the judge without consulting the protocol or the senior labels Jun 22, 2023
@sherlock-admin sherlock-admin added the Reward A payout will be made for this issue label Jun 27, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label High A valid High severity issue Reward A payout will be made for this issue
Projects
None yet
Development

No branches or pull requests

3 participants