sherlock-audit / 2023-05-perennial-judging

12 stars 9 forks source link

MohammedRizwan - Unhandled chainlink revert would lock price oracle access #240

Closed sherlock-admin closed 1 year ago

sherlock-admin commented 1 year ago

MohammedRizwan

medium

Unhandled chainlink revert would lock price oracle access

Summary

Chainlink's latestRoundData() is used which could potentially revert and make it impossible to query any prices. This could lead to permanent denial of service.

Vulnerability Detail

In ChainlinkAggregator.sol contract, getLatestRound() function is given by,

File:   perennial-oracle/contracts/types/ChainlinkAggregator.sol

    function getLatestRound(ChainlinkAggregator self) internal view returns (ChainlinkRound memory) {
        (uint80 roundId, int256 answer, , uint256 updatedAt, ) =
            AggregatorProxyInterface(ChainlinkAggregator.unwrap(self)).latestRoundData();
        return ChainlinkRound({roundId: roundId, timestamp: updatedAt, answer: answer});
    }

As seen above, getLatestRound() function makes use of Chainlink's latestRoundData() to get the latest price. However, there is no fallback logic to be executed when the access to the Chainlink data feed is denied by Chainlink's multisigs. Chainlink's multisigs can immediately block access to price feeds at will. Therefore, to prevent denial of service scenarios, it is recommended to query Chainlink price feeds using a defensive approach with Solidity’s try/catch structure. In this way, if the call to the price feed fails, the caller contract is still in control and can handle any errors safely and explicitly.

Impact

Call to latestRoundData could potentially revert and make it impossible to query any prices. This could lead to permanent denial of service.

Code Snippet

https://github.com/equilibria-xyz/perennial-mono/blob/b06d5145db62a312dd88dfcafef0f8e2166c5e32/packages/perennial-oracle/contracts/types/ChainlinkAggregator.sol#L32-L36

Openzeppelin reference-

Refer to https://blog.openzeppelin.com/secure-smart-contract-guidelines-the-dangers-of-price-oracles/ for more information regarding potential risks to account for when relying on external price feed providers.

Tool used

Manual Review

Recommendation

Surround the call to latestRoundData() with try/catch instead of calling it directly. In a scenario where the call reverts, the catch block can be used to call a fallback oracle or handle the error in any other suitable way.