QuantAMM

QuantAMM
49,600 OP
View results
Submission Details
Severity: low
Invalid

Missing Zero and Negative Value Checks in Oracle Data

Summary

The _getData and _getOracleData functions are responsible for retrieving and processing data from oracles. However, neither function validates whether the returned data is greater than zero. This lack of validation introduces critical vulnerabilities, including division by zero errors and propagation of invalid data, which can destabilize the contract and lead to incorrect operations.

Vulnerability Details

The _getData function retrieves data from multiple oracles and processes it sequentially. However, it does not ensure that the data returned by any oracle is greater than zero.

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; // 10^36 (i.e., 1 with 18 decimals * 10^18) to get the inverse with 18 decimals.
// 10**36 is automatically precomputed by the compiler, no explicit caching needed
}
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; // Return minimum timestamp
}
// depends which way the oracle conversion is happening
if (oracleConfig.invert) {
data = (data * 10 ** 18) / oracleRes;
} else {
data = (data * oracleRes) / 10 ** 18;
}
unchecked {
++i;
}
}
}

When the invert flag is true, the function attempts to calculate 10 ** 36 / data, which results in a division by zero if data is zero. This causes the contract to revert.

The _getOracleData function retrieves data from an individual oracle but does not validate that the returned data is greater than zero before assigning it to the OracleData struct.

function _getOracleData(OracleWrapper _oracle) private view returns (OracleData memory oracleResult) {
if (!approvedOracles[address(_oracle)]) return oracleResult; // Return empty timestamp if oracle is no longer approved, result will be discarded
(int216 data, uint40 timestamp) = _oracle.getData();
>> oracleResult.data = data;
oracleResult.timestamp = timestamp;
}

Invalid or zero data could bypass validation and be used in subsequent calculations or operations, leading to undesired outcomes.

Impact

Zero or negative values can lead to incorrect calculations and inconsistent results, potentially impacting users and the system’s reliability. Faulty operations due to invalid data could result in significant financial losses for users and stakeholders.

Tools Used

Manual Review

Recommendations

Introduce a validation step to ensure that all data returned from oracles is greater than zero before use.
_getData function

function _getData() internal view override returns (int216 data, uint40 timestamp) {
HopConfig memory firstOracle = oracles[0];
(data, timestamp) = firstOracle.oracle.getData();
+ require(data > 0, "INVLDDATA");
if (firstOracle.invert) {
data = 10 ** 36 / data; // 10^36 (i.e., 1 with 18 decimals * 10^18) to get the inverse with 18 decimals.
// 10**36 is automatically precomputed by the compiler, no explicit caching needed
}
// ...SNIP...
require(data > 0, "INVLDDATA");

_getOracleData function

function _getOracleData(OracleWrapper _oracle) private view returns (OracleData memory oracleResult) {
if (!approvedOracles[address(_oracle)]) return oracleResult; // Return empty timestamp if oracle is no longer approved, result will be discarded
(int216 data, uint40 timestamp) = _oracle.getData();
oracleResult.data = data;
+ require(data > 0, "INVLDDATA");
oracleResult.timestamp = timestamp;
}
Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

invalid_getData_negative_or_zero_price

Multihop will call ChainlinkOracle and the check is in it: `require(data > 0, "INVLDDATA");` MultiHop is just here to combine Chainlinks feed when there is no direct USD price feed for a token.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.