Skip to content

Latest commit

 

History

History
178 lines (147 loc) · 8 KB

File metadata and controls

178 lines (147 loc) · 8 KB

Tame Cider Turkey

Medium

MorphoLeverageStrategyExtension has Reliance on block.timestamp for Critical Time-Based Logic

Impact

The MorphoLeverageStrategyExtension contract utilizes block.timestamp to enforce time-based conditions for rebalancing operations.

This reliance on block.timestamp can be manipulated by miners within a permissible range, potentially leading to unintended behavior in the rebalance mechanism.

It is recommended to replace block.timestamp with a more reliable and tamper-resistant source, such as Chainlink’s Oracle-provided timestamp, to ensure the integrity of time-dependent functionalities.

Manipulation of block.timestamp by miners can lead to:

Timing Attacks: Miners could influence the execution timing of rebalances, potentially executing them more frequently or less frequently than intended.

Economic Exploits: Altered rebalance timings might result in suboptimal leverage ratios, leading to financial losses for token holders or opportunities for arbitrage.

Vulnerable Code

// https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/main/index-coop-smart-contracts/contracts/adapters/MorphoLeverageStrategyExtension.sol#L1248-L1290

    function _shouldRebalance(
        uint256 _currentLeverageRatio,
        uint256 _minLeverageRatio,
        uint256 _maxLeverageRatio
    )
        internal
        view
        returns(string[] memory, ShouldRebalance[] memory)
    {


        ShouldRebalance[] memory shouldRebalanceEnums = new ShouldRebalance[](enabledExchanges.length);


        for (uint256 i = 0; i < enabledExchanges.length; i++) {
            // If none of the below conditions are satisfied, then should not rebalance
            shouldRebalanceEnums[i] = ShouldRebalance.NONE;


            // If above ripcord threshold, then check if incentivized cooldown period has elapsed
            if (_currentLeverageRatio >= incentive.incentivizedLeverageRatio) {
                if (exchangeSettings[enabledExchanges[i]].exchangeLastTradeTimestamp.add(incentive.incentivizedTwapCooldownPeriod) < block.timestamp) {
                    shouldRebalanceEnums[i] = ShouldRebalance.RIPCORD;
                }
            } else {
                // If TWAP, then check if the cooldown period has elapsed
                if (twapLeverageRatio > 0) {
                    if (exchangeSettings[enabledExchanges[i]].exchangeLastTradeTimestamp.add(execution.twapCooldownPeriod) < block.timestamp) {
                        shouldRebalanceEnums[i] = ShouldRebalance.ITERATE_REBALANCE;
                    }
                } else {
                    // If not TWAP, then check if the rebalance interval has elapsed OR current leverage is above max leverage OR current leverage is below
                    // min leverage
                    if (
                        block.timestamp.sub(globalLastTradeTimestamp) > methodology.rebalanceInterval
                        || _currentLeverageRatio > _maxLeverageRatio
                        || _currentLeverageRatio < _minLeverageRatio
                    ) {
                        shouldRebalanceEnums[i] = ShouldRebalance.REBALANCE;
                    }
                }
            }
        }


        return (enabledExchanges, shouldRebalanceEnums);
    }

// https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/main/index-coop-smart-contracts/contracts/adapters/MorphoLeverageStrategyExtension.sol#L993-L1005

    /**
     * Validate that current leverage is below incentivized leverage ratio and cooldown / rebalance period has elapsed or outsize max/min bounds. Used
     * in rebalance() and iterateRebalance() functions
     */
    function _validateNormalRebalance(LeverageInfo memory _leverageInfo, uint256 _coolDown, uint256 _lastTradeTimestamp) internal view {
        require(_leverageInfo.currentLeverageRatio < incentive.incentivizedLeverageRatio, "Must be below incentivized leverage ratio");
        require(
            block.timestamp.sub(_lastTradeTimestamp) > _coolDown
            || _leverageInfo.currentLeverageRatio > methodology.maxLeverageRatio
            || _leverageInfo.currentLeverageRatio < methodology.minLeverageRatio,
            "Cooldown not elapsed or not valid leverage ratio"
        );
    }

// https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/main/index-coop-smart-contracts/contracts/adapters/MorphoLeverageStrategyExtension.sol#L1007-L1014

    /**
     * Validate that current leverage is above incentivized leverage ratio and incentivized cooldown period has elapsed in ripcord()
     */
    function _validateRipcord(LeverageInfo memory _leverageInfo, uint256 _lastTradeTimestamp) internal view {
        require(_leverageInfo.currentLeverageRatio >= incentive.incentivizedLeverageRatio, "Must be above incentivized leverage ratio");
        // If currently in the midst of a TWAP rebalance, ensure that the cooldown period has elapsed
        require(_lastTradeTimestamp.add(incentive.incentivizedTwapCooldownPeriod) < block.timestamp, "TWAP cooldown must have elapsed");
    }

// https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/main/index-coop-smart-contracts/contracts/adapters/MorphoLeverageStrategyExtension.sol#L1219-L1227

    /**
     * Update globalLastTradeTimestamp and exchangeLastTradeTimestamp values. This function updates both the exchange-specific and global timestamp so that the
     * epoch rebalance can use the global timestamp (since the global timestamp is always  equal to the most recently used exchange timestamp). This allows for
     * multiple rebalances to occur simultaneously since only the exchange-specific timestamp is checked for non-epoch rebalances.
     */
     function _updateLastTradeTimestamp(string memory _exchangeName) internal {
        globalLastTradeTimestamp = block.timestamp;
        exchangeSettings[_exchangeName].exchangeLastTradeTimestamp = block.timestamp;
     }

Mitigation

Replace block.timestamp with a secure and tamper-resistant time source provided by Chainlink Oracle.

import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";

contract MorphoLeverageStrategyExtension is BaseExtension {
    AggregatorV3Interface internal timeOracle;

    constructor(
        IBaseManager _manager,
        // ... other parameters
        address _timeOracle
    )
        public
        BaseExtension(_manager)
    {
        // Initialize the Chainlink Time Oracle
        timeOracle = AggregatorV3Interface(_timeOracle);
        // ... existing constructor code
    }

    /**
     * Retrieves the current timestamp from the Chainlink Oracle
     */
    function getCurrentTimestamp() internal view returns (uint256) {
        (
            , 
            int256 currentTime,
            ,
            ,
            
        ) = timeOracle.latestRoundData();
        return uint256(currentTime);
    }

    // Update the vulnerable code to use getCurrentTimestamp()
    function someFunction() internal {
        if (
            getCurrentTimestamp().sub(globalLastTradeTimestamp) > methodology.rebalanceInterval
            || _currentLeverageRatio > _maxLeverageRatio
            || _currentLeverageRatio < _minLeverageRatio
        ) {
            shouldRebalanceEnums[i] = ShouldRebalance.REBALANCE;
        }
    }
}

Locations

https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/main/index-coop-smart-contracts/contracts/adapters/MorphoLeverageStrategyExtension.sol#L1248-L1290
https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/main/index-coop-smart-contracts/contracts/adapters/MorphoLeverageStrategyExtension.sol#L993-L1005
https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/main/index-coop-smart-contracts/contracts/adapters/MorphoLeverageStrategyExtension.sol#L1007-L1014
https://github.com/sherlock-audit/2024-10-morpho-x-index/blob/main/index-coop-smart-contracts/contracts/adapters/MorphoLeverageStrategyExtension.sol#L1219-L1227

Reference

https://solodit.cyfrin.io/issues/m-06-blocktimestamp-or-deadline-code4rena-amun-amun-contest-git