Skip to content

Latest commit

 

History

History
76 lines (52 loc) · 2.79 KB

094.md

File metadata and controls

76 lines (52 loc) · 2.79 KB

Swift Lace Rat

Medium

Inadequate Stale Price Validation in Uniswap V3 Oracle-Based Price Calculations

Summary

In the NumaOracle.sol, the getV3SqrtHighestPrice function and related logic utilize Uniswap V3 oracle-based TWAP (Time Weighted Average Price) and spot prices without validating the freshness of the retrieved data. This creates a potential vulnerability, as the system could rely on stale or outdated price data, leading to inaccurate calculations or financial losses. Additionally, the absence of safeguards against the manipulation of spot prices exacerbates the risk.

Root Cause

The root cause of this vulnerability is the absence of a timestamp check to confirm the freshness of the price data retrieved from Uniswap V3's oracle and spot price. Neither the TWAP retrieval functions (getV3SqrtPriceAvg) nor the slot0() function for spot prices validate the age of the underlying price data.

https://github.com/sherlock-audit/2024-12-numa-audit/blob/main/Numa/contracts/NumaProtocol/NumaOracle.sol#L164-L185:

    function getV3SpotPrice(
        address _numaPool,
        uint _numaAmount
    ) external view returns (uint256) {
        (uint160 sqrtPriceX96, , , , , , ) = IUniswapV3Pool(_numaPool).slot0();
        uint256 numerator = (
            IUniswapV3Pool(_numaPool).token0() == token
                ? sqrtPriceX96
                : FixedPoint96.Q96
        );
        uint256 denominator = (
            numerator == sqrtPriceX96 ? FixedPoint96.Q96 : sqrtPriceX96
        );

        uint256 TokenPerNumaMulAmount = FullMath.mulDivRoundingUp(
            FullMath.mulDivRoundingUp(denominator, denominator, numerator),
            _numaAmount,
            numerator
        );

        return TokenPerNumaMulAmount;
    }

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

If the Uniswap oracle's observations are outdated or derived from a pool with insufficient activity, calculations will rely on prices that no longer reflect market reality. Incorrect or stale pricing data could result in overestimation or underestimation of asset values, causing potential financial losses to both users and the protocol.

PoC

No response

Mitigation

Validate that the TWAP data is up-to-date by checking the last update timestamp from the Uniswap V3 pool.

Example:

function isOracleUpdated(address _uniswapV3Pool, uint32 interval) internal view returns (bool) {
    (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) =
        IUniswapV3Pool(_uniswapV3Pool).observe([interval, 0]);
    uint256 lastUpdated = block.timestamp - secondsPerLiquidityCumulativeX128s[1];
    require(lastUpdated < FRESHNESS_THRESHOLD, "Price data is stale");
    return true;
}