Open sherlock-admin opened 1 year ago
Thanks - we had a long internal debate discussion about this.
We decided that it is best to make the parameters (such as epoch length) long enough such that this is extremely unlikely to happen.
We have done some extensive latency and heartbeat analysis on chainlink oracles - as well as had an in-details discussion about how gas price spikes can cause delays to prices being pushed on chain (a side note - this is why a large mewt/minimumExecutionWatingTime is required - otherwise a gas price spike/griefing attack would be more feasible). I'll link some of that to this issue in a bit if that is interesting to you.
Anyway - getting back to this issue - we believe it is better to leave the market paused if such an anomaly happens and give us time to analyse what happened. It is a sort of risk protection mechanism. Either we upgrade market for a fix (which will be under timelock), or we deprecate the market.
I think our users will appreciate our prudence.
One thing to consider is that withdrawals also won't be processed in this edge case (maybe a good think?). I'll have another chat with the team on that.
Agree that your solution is pretty benign too since there will just be no price change.
@WooSungD would be useful if you could post that graph of chainlink prices on the analysis we did.
For more context, a few weeks ago we had detailed disscussion with the chainlink team, as you can't even rely on the hearbeat with certainty.
E.g. the heartbeat of 27sec on polygon still showed outliers where we waited for up to 180 seconds in some cases for a new price because of big gas spikes. This is why we conducted the analysis so carefully, we want to make sure that we don't miss a chainlink price.
However if we do miss a price, the auto deprecation means the system fails very gracefully, the markets are paused and everyone can simply withdraw after a cooldown period.
Here are some graphs showing the distribution of heartbeat (in seconds) for ETH-USD price feed on Chainlink Polygon.
The outliers for the heartbeat mean that our MEWT needs to be longer (longer than max outlier necessarily) to prevent front-running.
The causes of outliers ito heartbeat were network congestion and gas spikes, according to the Chainlink team
After chatting with the chainlink team more on this, the one potential attack vector (that seems unrealistic) that I can point out is spamming the polygon chain to the point where it delays the chainlink price update from being mined until the point where no valid price exists.
This would be extremely expensive and simply cause the market to deprecate (no financial gain).
We still think this is a high severity issue as it can make the protocol malfunction
Downgrading to medium severity as it's clear to the judges a large part of the protocol is specifically engineered to handle this case.
Prior discussion of this issue before the audit can be found here: https://github.com/sherlock-audit/2022-11-float-capital/blob/090c1096aacc0e7dc31bc1d00a82357f9c76fbd4/README.md?plain=1#L163 and https://youtu.be/UjgqyKQSz7s?t=1619
WATCHPUG
high
An update gap in Chainlink's feed can malfunction the whole market
Summary
The
roundId
that is used for settling the price change and pushing thelatestExecutedEpochIndex
forward is strictly limited to be in a precise period of time. When there is no suchroundId
, the system will freeze and lock everyone out.Vulnerability Detail
The check at L127 makes it impossible to use a roundId that was created at a later time than
relevantEpochStartTimestampWithMEWT + EPOCH_LENGTH
.However, when the
EPOCH_LENGTH
is larger than the Chainlink feed's heartbeat length, or Chainlink failed to post a feed within the expected heartbeat for whatever reason, then it would be impossible to find a suitable roundId (as it does not exist) to push the epoch forward due to the rather strict limitation for the roundId.Impact
As a result, the whole system will malfunction and no one can enter or exit the market.
Code Snippet
https://github.com/sherlock-audit/2022-11-float-capital/blob/main/contracts/market/template/MarketCore.sol#L188-L195
Tool used
Manual Review
Recommendation
Consider allowing the
roundId
not to falls into the epoch, and use the previous roundId's price when that's the case: