The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: medium
Invalid

Price Oracles will return the wrong price for asset if underlying aggregator hits minAnswer

Summary

Chainlink aggregators have a built-in circuit breaker to prevent the price of an asset from deviating outside a predefined price range. This circuit breaker may cause the oracle to persistently return the minPrice instead of the actual asset price in the event of a significant price drop, as witnessed during the LUNA crash.

Vulnerability Details

OffchainAggregator.sol#L680-L684

int192 median = r.observations[r.observations.length/2];
require(minAnswer <= median && median <= maxAnswer, "median is out of min-max range");
r.hotVars.latestAggregatorRoundId++;
s_transmissions[r.hotVars.latestAggregatorRoundId] =
Transmission(median, uint64(block.timestamp));

ChainlinkAggregators have minPrice and maxPrice circuit breakers built into them. This prevents the aggregator from updating the price below the minPrice specified at contract creation. If an asset's price falls below the minPrice, the protocol continues to value the token at the minPrice rather than its real value.

In distributeAssets() the price of an asset could be largely inflated resulting in liquidation rewards being wrongly calculated.

File: LiquidationPool.sol
207: (,int256 priceEurUsd,,,) = Chainlink.AggregatorV3Interface(eurUsd).latestRoundData();
219: (,int256 assetPriceUsd,,,) = Chainlink.AggregatorV3Interface(asset.token.clAddr).latestRoundData();

LiquidationPool.sol#L207
LiquidationPool.sol#L209

Note that this problem also arises for all the data feeds, especially in the calculation of the collateral value of the vaults. The return value of euroCollateral() could be inflated allowing drastically larger amount of EUROs being minted.

Impact

In the event that an asset crashes (i.e. LUNA) the protocol can be manipulated to give out EUROs tokens at an inflated price.

Tools Used

Manual review

Recommendations

The returned answer of Price Oracles should be cross-checked against the minPrice/maxPrice and revert if the answer is outside of these bounds:

(,int256 priceEurUsd,,,) = Chainlink.AggregatorV3Interface(eurUsd).latestRoundData();
if (priceEurUsd >= maxPrice or priceEurUsd <= minPrice) revert();
(,int256 assetPriceUsd,,,) = Chainlink.AggregatorV3Interface(asset.token.clAddr).latestRoundData();
if (assetPriceUsd >= maxPrice or assetPriceUsd <= minPrice) revert();

This ensures that a false price will not be returned if the underlying asset's value hits the minPrice.

Updates

Lead Judging Commences

hrishibhat Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

chainlink-minanswer

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

chainlink-minanswer

Support

FAQs

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