QuantAMM

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

Lack of Price Deviation Guards in QuantAMM's Oracle Enables Portfolio Manipulation Through Extreme Price Movements

Summary

The ChainlinkOracle contract's _getData() implementation exposes critical vulnerabilities in QuantAMM's Temporal Function Market Making (TFMM) mechanism by lacking price deviation validation between consecutive oracle updates. Within QuantAMM's automated portfolio management framework, this vulnerability becomes particularly severe as the TFMM system continuously adjusts weights based on oracle price inputs.

The absence of deviation checks creates a dangerous scenario where QuantAMM's weight adjustment algorithm could execute extreme rebalancing operations based on manipulated or erroneous prices. This vulnerability is amplified by the protocol's composite pool architecture, where a single compromised price feed could trigger cascading rebalancing events across multiple interconnected strategies.

During periods of market volatility, the TFMM mechanism's reliance on continuous price updates becomes a critical point of failure. Flash crashes or price spikes could cause the protocol to execute rapid, unwarranted portfolio reallocations, potentially destabilizing entire strategy implementations. The risk is compounded in QuantAMM's BTF structure, where automated trading strategies could interpret manipulated price movements as legitimate trading signals, leading to systematic portfolio mismanagement.

Proof of Concept

https://github.com/Cyfrin/2024-12-quantamm/blob/main/pkg/pool-quantamm/contracts/ChainlinkOracle.sol#L27

function _getData() internal view override returns (int216, uint40) {
(, /*uint80 roundID*/ int data, , /*uint startedAt*/ uint timestamp, ) = /*uint80 answeredInRound*/
priceFeed.latestRoundData();
require(data > 0, "INVLDDATA");
data = data * int(10 ** normalizationFactor);
return (int216(data), uint40(timestamp));
}

Recommended mitigation steps

Implement price deviation validation with configurable thresholds:

contract ChainlinkOracle is OracleWrapper {
int256 private lastValidPrice;
uint256 public immutable maxPriceDeviation; // in basis points (e.g., 1000 = 10%)
constructor(address _chainlinkFeed, uint256 _maxDeviation) {
require(_maxDeviation > 0, "INVALID_DEVIATION");
maxPriceDeviation = _maxDeviation;
}
function _validatePriceDeviation(int256 newPrice, int256 oldPrice) internal view {
if (oldPrice == 0) return;
int256 priceChange = ((newPrice - oldPrice) * 10000) / oldPrice;
if (priceChange < 0) priceChange = -priceChange;
if (uint256(priceChange) > maxPriceDeviation) {
revert ExcessiveDeviation(oldPrice, newPrice, maxPriceDeviation);
}
}
function _getData() internal view override returns (int216, uint40) {
(, int256 data, , uint256 updatedAt, ) = priceFeed.latestRoundData();
int256 normalizedPrice = data * int256(10 ** normalizationFactor);
_validatePriceDeviation(normalizedPrice, lastValidPrice);
lastValidPrice = normalizedPrice;
return (int216(normalizedPrice), uint40(updatedAt));
}
}
Updates

Lead Judging Commences

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

invalid_chainlink_min_max_no_check

LightChaser: ## [Low-25] Chainlink answer is not compared against min/max values

Support

FAQs

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