The market openInterest
and skew
are set to zero any time a user is liquidated. This will lead to the market's accounting being wrong, resulting in multiple issues.
1) openInterest and skew can far exceed the MAX_OPEN_INTEREST and MAX_SKEW. This will lead to market makers potentialy having a high exposition to one side of the market.
2) Skew is used to calculate the funding velocity and funding rate. Skew being set to zero will result in the market having the lowest possible funding rate, so traders will not be deducted the funding fees that they should be.
In LiquidationBranch::liquidateAccounts, a new LiquidationContext struct is created to update the perp market's funding, open interest and skew, and the trading account's position. At the end, the following function is called:
perpMarket.updateOpenInterest(ctx.newOpenInterestX18, ctx.newSkewX18);
However, the ctx.newOpenInterestX18
and ctx.newSkewX18
are not assigned any value during the liquidation, so they will have the default value of 0. This means that the perpMarket's open interest and skew will be 0 after the liquidation.
Setting the open interest and skew to 0 on every liquidation makes the accounting of the protocol false and will jeopardize the LPs. As the protocol will lose track of the open interest and skew, users will effectively be able to open positions far beyond the MAX_SKEW
and MAX OPEN_INTEREST
. According to the sponsors (shared in a private thread) these maximum parameters exist in order to protect LPs, who are on the market maker side, from having too high an exposure to one side of the market. While the market making engine is beyond the scope of this audit, it is reasonable to assume that this is contradictory to the protocol's design, puts LPs at risk and can be exploited by malicious users.
In addition, the skew is also used to calculate the funding velocity and funding rate. When it is set to zero, the funding rate will be equal to the minimum of SD_UNIT
, leading to funding fees not being properly collected.
Manual review
This issue arises from a mitigation of another issue identified by the Cyfrin private audit. The line
has been removed because liquidations should be possible even if the open interest and skew are beyond the maximum (as they will be decreased by liquidations). However, this call also sets the values for the newOpenInterest
and newSkewX18
.
The logic for setting these should be implemented separately from the checkOpenInterestLimits
function and should still be done at the end of liquidateAccounts()
.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.