The Standard

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

No freshness check can lead to stale price data

Summary

LiquidationPool::distributeAssets() uses Chainlink price feeds but does not verify freshness of the data.

Vulnerability Details

The recommendation from Chainlink docs

Your application should track the latestTimestamp variable or use the updatedAt value from the
latestRoundData() function to make sure that the latest answer is recent enough for your application to use it.
If your application detects that the reported answer is not updated within the heartbeat or within time limits
that you determine are acceptable for your application, pause operation or switch to an alternate operation mode
while identifying the cause of the delay.

Speculations on potential causes for stale data generally center around economic drivers with dose of future gazing.

Impact

LiquidationPool::distributedAssets() is called by LiquidationPoolManager.runLiquidation() as an essential part of the liquidation process.

The liquidation process is the secondary pegging mechanism outlined in TheStandard whitepaper

With stale prices there are two possibilities are either over or under valuation of assets in LiquidationPool::distributedAssets().

  • Asset overvaluation: stakers looses out, paying more EUROs to the protocol for the assets.

  • Asset undervaluation: protocol looses out, taking fewer EUROs than it should from the stakers for the assets.

In the overall liquidation process, incorrect valuation can result in vaults being liquidated when should not be (based on L1 prices).

Tools Used

Manual review

Recommendations

From the Chainlink AggregatorV3Interface::latestRoundData() docs we can infer the use of updatedAt as input to a tolerance check.

Unfortunately with each price feed being able to a different heartbeat, you would need a per-feed tolerance configuration.
To provide that a wrapper around the price feed could be used, a decorator pattern, with the only change being required in deployment scripts (at an increase in gas for the added call).

Aggregator Decorator Contract

The intent is to provide the AggregatorV3Interface functions, the calls the aggregator but also performs addition behaviours, such as checking for stale data in latestRoundData().

contract AggregatorV3Decorator is AggregatorV3Interface {
private immutable AggregatorV3Interface feed;
private immutable uint256 toleranceTime;
constructor(AggregatorV3Interface _feed, uint256 _toleranceTime) {
feed =_feed;
toleranceTime = _toleranceTime;
}
function decimals() external view returns (uint8){
return feed.decimals();
}
function description() external view returns (string memory){
return feed.description();
}
function version() external view returns (uint256){
return feed.version();
}
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
){
(roundId,answer, startedAt, updatedAt, answeredInRound) = feed.getRoundData(_roundId);
}
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
){
(roundId,answer, startedAt, updatedAt, answeredInRound) = feed.latestRoundData();
require(block.timestamp - updatedAt < toleranceTime, "stale-price-feed");
}
}

Using the decorator

Create a decorator for each feed, then pass the decorators into the contracts instead of the feed in deployment.

LiquidationPool::eurUsd will be the EUR/USD decorator address, instead of the Chainlink price feed directly.
ITokenManager::Token::clAddr will be the Asset/USD decorator address, instead of the Chainlink price feed directly.

Updates

Lead Judging Commences

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Chainlink-price

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

Chainlink-price

Support

FAQs

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