QuantAMM

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

Oracle-Token Count Mismatch in QuantAMMWeightedPool Leading to Array Access Violation in UpdateRule

Summary

In the UpdateWeightRunner.sol where there's no validation between the number of oracles (_poolSettings.oracles.length) and the number of tokens during pool initialization. This mismatch will lead to array access violations in weight calculations, causing transaction reverts and effectively creating a Denial of Service (DoS) condition when performing an update for a valid pool

Vulnerability Details

  1. In setRuleForPool(), oracles are set without validation:

    function setRuleForPool(IQuantAMMWeightedPool.PoolSettings memory _poolSettings) external {
    require(_poolSettings.oracles.length > 0, "Empty oracles array");
    // Missing validation: _poolSettings.oracles.length == tokens.length
    poolOracles[msg.sender] = optimisedHappyPathOracles;
    }
  2. During weight updates, _getData() gets oracle data based on the oracles that are assigned to the pool, while _performUpdateAndGetData() gets getNormalizedWeights based on the Weights of the assets in the pool using the total number of tokens:

    function _getNormalizedWeights() internal view virtual returns (uint256[] memory) {
    uint256 totalTokens = _totalTokens;
    // ... some codes
    }

    within the perform update:

    function _performUpdateAndGetData(
    address _poolAddress,
    PoolRuleSettings memory _ruleSettings
    ) private returns (int256[] memory) {
    uint256[] memory currentWeightsUnsigned = IWeightedPool(_poolAddress).getNormalizedWeights();
    int256[] memory currentWeights = new int256[]();
    for (uint i; i < currentWeights.length; ) {
    currentWeights[i] = int256(currentWeightsUnsigned[i]);
    unchecked {
    i++;
    }
    }
    (int256[] memory updatedWeights, int256[] memory data) = _getUpdatedWeightsAndOracleData(
    _poolAddress,
    currentWeights,
    _ruleSettings
    );
    // ...some codes
    }

    _calculateQuantAMMMovingAverage() assumes array lengths match:

    function _calculateQuantAMMMovingAverage(
    int256[] memory _prevMovingAverage,
    int256[] memory _newData, // From oracles
    int128[] memory _lambda,
    uint _numberOfAssets // From token count
    ) internal pure returns (int256[] memory) {
    + // Will revert if _newData.length < _numberOfAssets
    for (uint i; i < _numberOfAssets; ) {
    int256 movingAverageI = _prevMovingAverage[i];
    newMovingAverage[i] = movingAverageI + oneMinusLambda.mul(_newData[i] - movingAverageI);
    unchecked { ++i; }
    }
    }

Impact

  • If oracle count < token count: The loop in _calculateQuantAMMMovingAverage will attempt to access non-existent array indices in _newData, causing a revert

  • If oracle count > token count: Extra oracle data will be ignored but still cause inconsistency

Tools Used

Recommendations

Add validation during pool initialization

Updates

Lead Judging Commences

n0kto Lead Judge 7 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.