QuantAMM

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

Lack of Oracle Round Completion Check in QuantAMM Allows Rebalancing on Incomplete Price Data

Summary

The ChainlinkOracle contract's _getData() function fails to validate round completion status when fetching price data for QuantAMM's TFMM operations. The function omits the critical check between answeredInRound and roundId returned by the Chainlink oracle's latestRoundData() function.

In QuantAMM's continuous rebalancing environment, accepting incomplete oracle rounds creates severe vulnerabilities. The TFMM mechanism relies on accurate price data to update pool weights and execute portfolio strategies. Incomplete rounds can lead to incorrect weight calculations, causing the entire rebalancing mechanism to make premature or incorrect adjustments.

The risk is amplified in QuantAMM's architecture because:

  • Temporal function market making depends on precise price data for weight adjustments

  • Composite pools could propagate incorrect rebalancing actions across multiple strategies

  • Automated trading decisions based on preliminary data could lead to systemic portfolio misalignments

  • BTF value calculations using unconfirmed prices affect the entire fund structure

  • Strategy execution based on incomplete rounds could trigger unnecessary rebalancing operations

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 round completion validation in the _getData function:

function _getData() internal view override returns (int216, uint40) {
(
uint80 roundId,
int256 data,
,
uint256 updatedAt,
uint80 answeredInRound
) = priceFeed.latestRoundData();
// Validate round completion
if (answeredInRound < roundId) {
revert IncompleteRound(roundId, answeredInRound);
}
require(data > 0, "INVLDDATA");
data = data * int(10 ** normalizationFactor);
return (int216(data), uint40(updatedAt));
}
Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

invalid_chainlink_staled_data_updateAt_roundId_known_issue

LightChaser: ## [Medium-4] Insufficient oracle validation

Support

FAQs

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