Summary
On some contracts, they get Oracle data but do not check if the timestamp is stale.
Vulnerability Details
On MultiHopOracle::_getData it just checks if the timestamp from firstOracle is greater than oracleConfig then timestamp from firstOracle will be accepted.
But it does not check any freshness logic.
function _getData() internal view override returns (int216 data, uint40 timestamp) {
HopConfig memory firstOracle = oracles[0];
@> (data, timestamp) = firstOracle.oracle.getData();
if (firstOracle.invert) {
data = 10 ** 36 / data;
}
uint256 oracleLength = oracles.length;
for (uint i = 1; i < oracleLength; ) {
HopConfig memory oracleConfig = oracles[i];
(int216 oracleRes, uint40 oracleTimestamp) = oracleConfig.oracle.getData();
@> if (oracleTimestamp < timestamp) {
timestamp = oracleTimestamp;
}
if (oracleConfig.invert) {
data = (data * 10 ** 18) / oracleRes;
} else {
data = (data * oracleRes) / 10 ** 18;
}
unchecked {
++i;
}
}
}
Also there should be freshness logic for those:
function _getData() internal view override returns (int216, uint40) {
(, int data, , uint timestamp, ) =
priceFeed.latestRoundData();
require(data > 0, "INVLDDATA");
data = data * int(10 ** normalizationFactor);
return (int216(data), uint40(timestamp));
}
function getData() public view returns (int216 data, uint40 timestamp) {
(data, timestamp) = _getData();
require(timestamp > 0, "INVORCLVAL");
}
Impact
It can accept a stale price and this will affect the calculation of the fund logic.
Tools Used
Manually Reviewed
Recommendations
Either add freshness logic on OracleWapper::getData function's timestamp or add on those who are using it.
Add freshness logic like UpdateWeightRunner::_getData