Tame Cider Turkey
Medium
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.
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.
// 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;
}
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;
}
}
}
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
https://solodit.cyfrin.io/issues/m-06-blocktimestamp-or-deadline-code4rena-amun-amun-contest-git