Skip to content

Latest commit

 

History

History
142 lines (87 loc) · 3.97 KB

File metadata and controls

142 lines (87 loc) · 3.97 KB

Breezy Basil Toad

Medium

incorrect fee handling will cause a revert

Summary

the leverage function increases the leverage of a given collateral position by retrieving borrow tokens and trading it for collateral token and deposits collateral token however when executing the trade the function does not account for the protocol fee when calculating the minNotionalReceiveQuantity

the lever function calls

  function lever(
    ISetToken _setToken,
    uint256 _borrowQuantityUnits,
    uint256 _minReceiveQuantityUnits,
    string memory _tradeAdapterName,
    bytes memory _tradeData
)
    external
    nonReentrant
    onlyManagerAndValidSet(_setToken)
{
    MarketParams memory setMarketParams = marketParams[_setToken]; 
    require(setMarketParams.collateralToken != address(0), "Collateral not set");


    // For levering up, send quantity is derived from borrow asset and receive quantity is derived from
    // collateral asset
    ActionInfo memory leverInfo = _createAndValidateActionInfo(
        _setToken,
        IERC20(setMarketParams.loanToken),
        IERC20(setMarketParams.collateralToken),
        _borrowQuantityUnits,
        _minReceiveQuantityUnits,
        _tradeAdapterName,
        true
    );


    _borrow(leverInfo.setToken, setMarketParams, leverInfo.notionalSendQuantity)


    uint256 postTradeReceiveQuantity = _executeTrade(leverInfo, IERC20(setMarketParams.loanToken), IERC20(setMarketParams.collateralToken), _tradeData); ////@audit


    uint256 protocolFee = _accrueProtocolFee(_setToken, IERC20(setMarketParams.collateralToken), postTradeReceiveQuantity);


    uint256 postTradeCollateralQuantity = postTradeReceiveQuantity.sub(protocolFee);


    _deposit(leverInfo.setToken, setMarketParams, postTradeCollateralQuantity);


    _sync(leverInfo.setToken);





function _executeTrade(
    ActionInfo memory _actionInfo,
    IERC20 _sendToken,
    IERC20 _receiveToken,
    bytes memory _data
)
    internal
    returns (uint256)
{
    ISetToken setToken = _actionInfo.setToken;
    uint256 notionalSendQuantity = _actionInfo.notionalSendQuantity;


    setToken.invokeApprove(
        address(_sendToken),
        _actionInfo.exchangeAdapter.getSpender(),
        notionalSendQuantity
    );


    (
        address targetExchange,
        uint256 callValue,
        bytes memory methodData
    ) = _actionInfo.exchangeAdapter.getTradeCalldata(
        address(_sendToken),
        address(_receiveToken),
        address(setToken),
        notionalSendQuantity,
        _actionInfo.minNotionalReceiveQuantity,
        _data
    );


    setToken.invoke(targetExchange, callValue, methodData);


    uint256 receiveTokenQuantity = _receiveToken.balanceOf(address(setToken)).sub(_actionInfo.preTradeReceiveTokenBalance);
    require(
        receiveTokenQuantity >= _actionInfo.minNotionalReceiveQuantity,
        "Slippage too high" ////@audit
    );


    return receiveTokenQuantity;

as we can see here if the receivequantity is less than minNotionalReceiveQuantity the function reverts this fails to account for the protocol fee when executing the trade however it accounts for the fee after the trade is executed

Root Cause

https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/2f125406e0dd3b1fc029b9a47fe97bfbf906fce2/index-protocol/contracts/protocol/modules/v1/MorphoLeverageModule.sol#L275

https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/2f125406e0dd3b1fc029b9a47fe97bfbf906fce2/index-protocol/contracts/protocol/modules/v1/MorphoLeverageModule.sol#L783-L822

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

temporary dos

PoC

No response

Mitigation

account for the protocol fee when executing the trade