Summary
The protocol utilizes reserved oracles for additional fault tolerance. But in case of reverting in the OracleWrapper.getData function the other reserved oracles are not called.
Vulnerability Details
The UpdateWeightRunner._getData can throw an error when "No fresh oracle values available". As mentioned in the comment this should rarely happen. But in fact reverts OracleWrapper.getData function can interrupt the function execution early:
function _getData(address _pool, bool internalCall) private view returns (int256[] memory outputData) {
require(internalCall || (approvedPoolActions[_pool] & MASK_POOL_GET_DATA > 0), "Not allowed to get data");
address[] memory optimisedOracles = poolOracles[_pool];
uint oracleLength = optimisedOracles.length;
uint numAssetOracles;
outputData = new int256[](oracleLength);
uint oracleStalenessThreshold = IQuantAMMWeightedPool(_pool).getOracleStalenessThreshold();
for (uint i; i < oracleLength; ) {
OracleData memory oracleResult;
>> oracleResult = _getOracleData(OracleWrapper(optimisedOracles[i]));
if (oracleResult.timestamp > block.timestamp - oracleStalenessThreshold) {
outputData[i] = oracleResult.data;
} else {
unchecked {
numAssetOracles = poolBackupOracles[_pool][i].length;
}
for (uint j = 1 ; j < numAssetOracles; ) {
>> oracleResult = _getOracleData(
OracleWrapper(poolBackupOracles[_pool][i][j])
);
if (oracleResult.timestamp > block.timestamp - oracleStalenessThreshold) {
break;
} else if (j == numAssetOracles - 1) {
>> revert("No fresh oracle values available");
}
unchecked {
++j;
}
}
outputData[i] = oracleResult.data;
}
unchecked {
++i;
}
}
}
OracleWrapper.sol
function getData() public view returns (int216 data, uint40 timestamp) {
(data, timestamp) = _getData();
>> require(timestamp > 0, "INVORCLVAL");
}
ChainlinkOracle.sol
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));
}
Impact
Temporary blocking core functionality, unexpected behavior.
Tools used
Manual Review
Recommendations
Consider return zero value in the oracleResult variable instead of revert.