code-423n4 / 2021-11-vader-findings

0 stars 0 forks source link

Incorrect Accrual Of `sumNative` and `sumUSD` In Producing Consultation Results #260

Closed code423n4 closed 2 years ago

code423n4 commented 2 years ago

Handle

leastwood

Vulnerability details

Vulnerability details

Impact

The TwapOracle.consult() function iterates over all token pairs which belong to either VADER or USDV` and then calculates the price of the respective asset by using both UniswapV2 and Chainlink price data. This helps to further protect against price manipulation attacks as the price is averaged out over the various registered token pairs.

Let's say we wanted to query the price of USDV, we would sum up any token pair where USDV == pairData.token0.

The sum consists of the following:

Consider the following example:

I'd classify this issue as high risk as the oracle returns false results upon being consulted. This can lead to issues in other areas of the protocol that use this data in performing sensitive actions.

Proof of Concept

https://github.com/code-423n4/2021-11-vader/blob/main/contracts/twap/TwapOracle.sol#L115-L157

Similar working implementation listed below:

Tools Used

Manual code review.

Recommended Mitigation Steps

To calculate the correct consultation of a given token, the returned result should consist of a sum of priceUSD * token.decimals() * priceNative divided by the number of calculations. This should correctly take the average token pair price.

The following snippet of code details the relevant fix:

    function consult(address token) public view returns (uint256 result) {
        uint256 pairCount = _pairs.length;

        for (uint256 i = 0; i < pairCount; i++) {
            PairData memory pairData = _pairs[i];

            if (token == pairData.token0) {
                //
                // TODO - Review:
                //   Verify price1Average is amount of USDV against 1 unit of token1
                //

                priceNative = pairData.price1Average.mul(1).decode144(); // native asset amount
                if (pairData.price1Average._x != 0) {
                    require(priceNative != 0);
                } else {
                    continue; // should skip newly registered assets that have not been updated yet.
                }

                (
                    uint80 roundID,
                    int256 price,
                    ,
                    ,
                    uint80 answeredInRound
                ) = AggregatorV3Interface(_aggregators[pairData.token1])
                        .latestRoundData();

                require(
                    answeredInRound >= roundID,
                    "TwapOracle::consult: stale chainlink price"
                );
                require(
                    price != 0,
                    "TwapOracle::consult: chainlink malfunction"
                );
                priceUSD = uint256(price) * (10**10);
                result += ((priceUSD * IERC20Metadata(token).decimals()) * priceNative);
            }
        }
        require(sumNative != 0, "TwapOracle::consult: Sum of native is zero");
        return result;
    }
SamSteinGG commented 2 years ago

The TWAP oracle module has been completely removed and redesigned from scratch as LBTwap that is subject of the new audit.