The Standard

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

Missing checks for whether the Arbitrum Sequencer is live can lead to stale prices and unfair liquidations

Summary

Since the contracts will be deployed on Arbitrum, using Chainlink in L2s (e.g. Arbitrum) requires checks whether the sequencer is down so that stale prices can be avoided. The sequencer downtime can be leveraged by malicious actors to take advantage of the incorrect price reporting as well as it can lead to unfair liquidations due to stale price feeds.

Vulnerability Details

In the LiquidationPool.sol there are Chainlink price oracles being utilized to fetch Asset/USD price as well as EUR/USD price, although no L2 Sequencer uptime checks are performed.

(,int256 priceEurUsd,,,) = Chainlink.AggregatorV3Interface(eurUsd).latestRoundData();
(,int256 assetPriceUsd,,,) = Chainlink.AggregatorV3Interface(asset.token.clAddr).latestRoundData();

Chainlink recommends when deploying on L2s (Arbitrum) to check for the sequencer uptime. If the Arbitrum Sequencer goes down, oracle data will not be kept up to date, and thus can become stale. Although the prices are stale, users can continue to interact with the protocol while oracle feeds are stale. This can lead to unfair calculations when it comes to the distributions of assets during liquidations, incorrect calculations related to EUROs burning, as well as unfair liquidations.

It should also be noted that price feeds are utilized in the calculation of the euroCollateral() as well as the maxMintable() which are key functions that determine whether a pool has become undercollateralized, if returned prices are stale due to L2 Sequencer downtime, this can lead to incorrect calculations and unfair liquidations.

//Calculating whether a vault is undercollateralized
function undercollateralised() public view returns (bool) {
return minted > maxMintable();
}
// Calculation of the Euro Collateral
function euroCollateral() private view returns (uint256 euros) {
ITokenManager.Token[] memory acceptedTokens = getTokenManager().getAcceptedTokens();
for (uint256 i = 0; i < acceptedTokens.length; i++) {
ITokenManager.Token memory token = acceptedTokens[i];
euros += calculator.tokenToEurAvg(token, getAssetBalance(token.symbol, token.addr));
}
}
// Calculation of Max Mintable
function maxMintable() private view returns (uint256) {
return euroCollateral() * ISmartVaultManagerV3(manager).HUNDRED_PC()
/ ISmartVaultManagerV3(manager).collateralRate();
}

These functions are dependent on tokenToEurAvg (part of the PriceCalculator.sol) which utilize Chainlink feeds, but have no Sequencer uptime checks:

function tokenToEurAvg(ITokenManager.Token memory _token, uint256 _tokenValue) external view returns (uint256) {
Chainlink.AggregatorV3Interface tokenUsdClFeed = Chainlink.AggregatorV3Interface(_token.clAddr);
uint256 scaledCollateral = _tokenValue * 10 ** getTokenScaleDiff(_token.symbol, _token.addr);
uint256 collateralUsd = scaledCollateral * avgPrice(4, tokenUsdClFeed);
(, int256 eurUsdPrice,,,) = clEurUsd.latestRoundData();
return collateralUsd / uint256(eurUsdPrice);

Other affected functions include swap (due to the price feed dependency in the calculateMinimumAmountOut() function as well.

Impact

Missing checks for L2 Sequencer downtime can lead to stale prices being reported whilst users are still able to interact with the protocol, this can result in unfair liquidations as well as incorrect distribution of assets during liquidations. This can also affect swaps due to the swap()'s dependency on the minimumAmountOut which utilizes price feeds.

Tools Used

  • Manual Review

Recommendations

Please refer to the Chainlink documentation for proper implementation of L2 Sequencer uptime checks through feeds:
https://docs.chain.link/data-feeds/l2-sequencer-feeds

As well as a blog article from Chainlink on the deployment of contracts on Arbitrum which mentions a Sequencer Health check through oracles:
https://blog.chain.link/how-to-use-chainlink-price-feeds-on-arbitrum/#almost_done!_meet_the_l2_sequencer_health_flag

Updates

Lead Judging Commences

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

Arbitrum-sequncer

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

Arbitrum-sequncer

Support

FAQs

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