DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: medium
Valid

User might be unfairly liquidated after L2 Sequencer grace period

Summary

User might be unfairly liquidated after L2 Sequencer grace period.

Vulnerability Details

The protocol implements a L2 sequencer downtime check in the ChainlinkUtil. In the event of sequencer downtime (as well as a grace period following recovery), liquidations are disabled for the rightful reasons.

if (address(sequencerUptimeFeed) != address(0)) {
try sequencerUptimeFeed.latestRoundData() returns (
uint80, int256 answer, uint256 startedAt, uint256, uint80
) {
bool isSequencerUp = answer == 0;
if (!isSequencerUp) {
@> revert Errors.OracleSequencerUptimeFeedIsDown(address(sequencerUptimeFeed));
}
uint256 timeSinceUp = block.timestamp - startedAt;
if (timeSinceUp <= Constants.SEQUENCER_GRACE_PERIOD_TIME) {
@> revert Errors.GracePeriodNotOver();
}
} catch {
revert Errors.InvalidSequencerUptimeFeedReturn();
}
}

At the same time, user won't be able to create order nor any order can be filled. This is problematic because when the Arbitrum sequencer is down and then comes back up, all Chainlink price updates will become available on Arbitrum within a very short time. This leaves users no time to react to the price changes which can lead to unfair liquidations.

Even if deposit is still allowed during the grace period, it is unfair to the user as they are forced to do so, not to mention that some users may not have enough funds to deposit.

Impact

User might be unfairly liquidated after L2 Sequencer grace period.

Tools Used

Manual Review

Recommendations

Order should be allowed to be created and filled during sequencer grace period, this can be achieved by skipping SEQUENCER_GRACE_PERIOD_TIME checking.

function getPrice(
IAggregatorV3 priceFeed,
uint32 priceFeedHeartbeatSeconds,
IAggregatorV3 sequencerUptimeFeed,
+ bool skipGracePeriodChecking
)
internal
view
returns (UD60x18 price)
{
...
if (address(sequencerUptimeFeed) != address(0)) {
try sequencerUptimeFeed.latestRoundData() returns (
uint80, int256 answer, uint256 startedAt, uint256, uint80
) {
bool isSequencerUp = answer == 0;
if (!isSequencerUp) {
revert Errors.OracleSequencerUptimeFeedIsDown(address(sequencerUptimeFeed));
}
uint256 timeSinceUp = block.timestamp - startedAt;
- if (timeSinceUp <= Constants.SEQUENCER_GRACE_PERIOD_TIME) {
+ if (!skipGracePeriodChecking && timeSinceUp <= Constants.SEQUENCER_GRACE_PERIOD_TIME) {
revert Errors.GracePeriodNotOver();
}
} catch {
revert Errors.InvalidSequencerUptimeFeedReturn();
}
}
...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

User might be unfairly liquidated after L2 Sequencer grace period

Appeal created

h2134 Submitter
over 1 year ago
h2134 Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

User might be unfairly liquidated after L2 Sequencer grace period

Support

FAQs

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

Give us feedback!