Closed sherlock-admin closed 8 months ago
1 comment(s) were left on this issue during the judging contest.
takarez commented:
invalid: i believe this is the intended behavior; that it should revert whenever there is a stale prices thats more than the maxDiffPercent, take a look
The protocol team fixed this issue in PR/commit https://github.com/dhedge/flatcoin-v1/pull/270.
Stryder
medium
[M-1]
OracleModule::_getPrice()
will revert if either one of the oracles fails, causing DOSSummary
In the current implementation of
OracleModule
, theOracleModule::maxDiffPercent
is checked before the output from the Pyth oracle is checked for its validity. This means that if either of the two oracles returns incorrect results or stale prices, the whole transaction reverts. This not only defeats the purpose of having two oracles, but it also makes the_getPrice()
function 25% more likely to revert.Vulnerability Detail
Even though the protocol uses two oracles, if either one of them returns incorrect prices and the price difference is greater than
OracleModule::maxDiffPercent
, the whole transaction will revert. This can cause DOS for users, keepers, and modules that are calling a lot of time-sensitive functions. Consider these scenarios:1) Chainlink Oracle falters: In this case, the whole transaction will revert, thus no prices will be returned.
2) Pyth Oracle falters: In this case, the
offchainInvalid
parameter will be returned as false, but since the data is incorrect, let's assume that the returned offchainPrice is such that the onChainPrice difference and offChainPrice difference are greater than theOracleModule::maxDiffPercent
. This means that this will also fail.Impact
A stale/incorrect price can cause the malfunction of multiple features across the protocol:
1) A lot of functions use
OracleModule::_getPrice()
to fetch the price of the tokens. Functions likeannounceLeverageAdjust()
,announceLeverageClose()
,executeOpen()
,executeClose()
,liquidate()
, etc., many of which are time-sensitive functions.2) Users/Keepers can miss out on liquidations, since the tokens that are used are volatile, the prices can shift a lot. So, if an oracle suddenly stops working and a position is undercollateralized, it won't be able to get liquidation until both of the oracles have started working properly.
3) If the problem persists, the protocol could remain in a paused state as all the actors would be DOSed and won't be able to do anything.
Code Snippet
Link to Code Snippet
Tool used
Manual Review
Recommendation
Consider returning another parameter
onchainInvalid
parameter from_getOnchainPrice()
function call that tells if the price returned from the chainlink oracle is valid or not and alastGoodPrice
to store the most recent valid price that was obtained from the oracle . Change the checks to something like thisSome important links :
https://0xmacro.com/blog/how-to-consume-chainlink-price-feeds-safely/ https://blog.openzeppelin.com/secure-smart-contract-guidelines-the-dangers-of-price-oracles
Duplicate of #177