QuantAMM

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

Lack of Circuit Breakers in QuantAMM Oracle Enables Automated Portfolio Destruction During Market Stress

Summary

The ChainlinkOracle contract's lack of circuit breaker protection fundamentally undermines QuantAMM's TFMM mechanism. The _getData() function processes all price updates without circuit breaker controls, leaving the automated portfolio management system exposed during extreme market conditions.

In QuantAMM's context, this vulnerability becomes particularly dangerous because the TFMM system continuously executes weight adjustments based on price inputs. When extreme market movements occur, the absence of circuit breakers allows the temporal function to continue adjusting weights without restriction, potentially causing a cascade of harmful portfolio rebalancing actions. The automated nature of TFMM means that these adjustments happen deterministically, regardless of market stress conditions.

The composite pool structure amplifies this risk, as extreme price movements in one pool can trigger automated rebalancing across multiple interconnected strategies. BTF operations become especially vulnerable as rapid portfolio adjustments could lead to significant value destruction through forced rebalancing at unfavorable prices. The temporal function's continuous operation without circuit breaker protection means that strategy drift could accelerate during market stress, leading to systemic portfolio misalignment.

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 a comprehensive circuit breaker mechanism:

contract ChainlinkOracle is OracleWrapper {
bool public circuitBreakerTriggered;
uint256 public circuitBreakerExpiry;
int256 public lastValidPrice;
uint256 public constant CIRCUIT_BREAKER_DURATION = 1 hours;
uint256 public constant RECOVERY_THRESHOLD = 1000; // 10% in basis points
event CircuitBreakerTriggered(int256 price, int256 lastValidPrice);
event CircuitBreakerReset();
function _checkCircuitBreaker(int256 normalizedPrice) internal {
if (circuitBreakerTriggered) {
require(
block.timestamp > circuitBreakerExpiry,
"Circuit breaker active"
);
int256 priceChange = ((normalizedPrice - lastValidPrice) * 10000) / lastValidPrice;
if (priceChange < 0) priceChange = -priceChange;
if (uint256(priceChange) <= RECOVERY_THRESHOLD) {
circuitBreakerTriggered = false;
emit CircuitBreakerReset();
} else {
circuitBreakerExpiry = block.timestamp + CIRCUIT_BREAKER_DURATION;
revert("Price movement exceeds recovery threshold");
}
}
// Check if we need to trigger circuit breaker
int256 priceChange = ((normalizedPrice - lastValidPrice) * 10000) / lastValidPrice;
if (priceChange < 0) priceChange = -priceChange;
if (uint256(priceChange) > RECOVERY_THRESHOLD) {
circuitBreakerTriggered = true;
circuitBreakerExpiry = block.timestamp + CIRCUIT_BREAKER_DURATION;
emit CircuitBreakerTriggered(normalizedPrice, lastValidPrice);
revert("Circuit breaker triggered");
}
lastValidPrice = normalizedPrice;
}
function _getData() internal view override returns (int216, uint40) {
(, int256 data, , uint256 updatedAt, ) = priceFeed.latestRoundData();
int256 normalizedPrice = data * int(10 ** normalizationFactor);
_checkCircuitBreaker(normalizedPrice);
return (int216(normalizedPrice), uint40(updatedAt));
}
}

The circuit breaker protection prevents catastrophic cascades while allowing for orderly market recovery during extreme conditions. Parameters should be carefully calibrated based on asset volatility and market depth.

Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas / Admin is trusted / Pool creation is trusted / User mistake / Suppositions

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

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