DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: low
Invalid

The skew of a market could go over the maxSkew due to incorrect assumption

Summary

The skew of a market could go over the maxSkew due to incorrect assumption

Vulnerability Details

Every market has a skew and open interest. For example, imagine there are 3 positions, 2 longs and 1 short, all with a size of 50. The skew is a number that essentially shows whether longs or shorts overpower. In this case, skew is as the longs clearly overpower the shorts. The open interest is the total size of open positions so 150. Whenever a user opens a position, there is this function:

function checkOpenInterestLimits(
Data storage self,
SD59x18 sizeDelta,
SD59x18 oldPositionSize,
SD59x18 newPositionSize
)
internal
view
returns (UD60x18 newOpenInterest, SD59x18 newSkew)
{
// load max & current open interest for this perp market uint128 -> UD60x18
UD60x18 maxOpenInterest = ud60x18(self.configuration.maxOpenInterest);
UD60x18 currentOpenInterest = ud60x18(self.openInterest);
// calculate new open interest which would result from proposed trade
// by subtracting old position size then adding new position size to
// current open interest
newOpenInterest = currentOpenInterest.sub(oldPositionSize.abs().intoUD60x18()).add(newPositionSize.abs().intoUD60x18());
// if new open interest would be greater than this market's max open interest,
// we still want to allow trades as long as they decrease the open interest. This
// allows traders to reduce/close their positions in markets where protocol admins
// have reduced the max open interest to reduce the protocol's exposure to a given
// perp market
if (newOpenInterest.gt(maxOpenInterest)) {
// is the proposed trade reducing open interest?
bool isReducingOpenInterest = currentOpenInterest.gt(newOpenInterest);
// revert if the proposed trade isn't reducing open interest
if (!isReducingOpenInterest) {
revert Errors.ExceedsOpenInterestLimit(self.id, maxOpenInterest.intoUint256(), newOpenInterest.intoUint256());
}
}
// load max & current skew for this perp market uint128 -> UD60x18 -> SD59x18
SD59x18 maxSkew = ud60x18(self.configuration.maxSkew).intoSD59x18();
// int128 -> SD59x18
SD59x18 currentSkew = sd59x18(self.skew);
// calculate new skew
newSkew = currentSkew.add(sizeDelta);
// similar logic to the open interest check; if the new skew is greater than
// the max, we still want to allow trades as long as they decrease the skew
if (newSkew.abs().gt(maxSkew)) {
bool isReducingSkew = currentSkew.abs().gt(newSkew.abs());
if (!isReducingSkew) {
revert Errors.ExceedsSkewLimit(self.id, maxSkew.intoUint256(), newSkew.intoInt256());
}
}
}

It essentially doesn't allow positions that would put the skew or open interest above their maximums to go through.

Whenever a liquidation occurs, we have the following line and comments above it:

// update perp market's open interest and skew; we don't enforce ipen
// interest and skew caps during liquidations as:
// 1) open interest and skew are both decreased by liquidations
// 2) we don't want liquidation to be DoS'd in case somehow those cap
// checks would fail
perpMarket.updateOpenInterest(ctx.newOpenInterestX18, ctx.newSkewX18);

From the comments, we can see that the function checkOpenInterestLimits() is not called because firstly, the open interest and skew are decreased by liquidations, thus there is no point in checking for that and also, because they don't want to cause a potential DoS in case there is somehow a way that could actually not be true. Firstly, there is another issue here which we have to assume doesn't exist and that is the fact that the arguments provided to updateOpenInterest() are both 0 due to not ctx.newOpenInterestX18 and newSkewX18 not having any values given which is a huge mistake. We have to assume it is fixed as otherwise the issue that I will explain now is not actually possible as the open interest and skew are always set to 0, thus they can not actually go above their maximums.

It says that the open interest and skew are both decreased by a liquidation. However, that is not actually true. Imagine there are 4 positions with the following sizes (minus in front means a short): 100, -150, 100, -50. Let's assume that the maximum skew is 100. From earlier, we know that the open interest for that position for these positions would be . The skew would go (for each new position) from 100, to -50, to 50, to finally 0. Now, let's imagine that the position with size of -150 gets liquidated. The open interest would decrease, as explained by the comment, and the open interest would now be 250. The skew however will go to 150 while the maximum skew in our example was 100. The skew will clearly not always decrease and even if it did decrease, a skew of -150 is still more than the maximum skew due to how a skew is supposed to be used and how it also is used in checkOpenInterestLimits() (by using absolute values, thus a skew of -150 is converted into its absolute value of 150 which is more than 100).

Impact

The skew of a market could go over the maxSkew due to incorrect assumption

Tools Used

Manual Review

Recommendations

Fix is not trivial as if you want to enforce the skews, then it would lead to reverts in some cases. If you decide not to enforce them, you have to know that the skew can in fact go over the maximum and accept the risk.

Updates

Lead Judging Commences

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

The skew of a market could go over the maxSkew due to bad assumption in checkOpenInterestLimits (after the fix of "`liquidateAccounts` calls `updateOpenInterest` with 0 OI and skew")

Appeal created

samuraii77 Submitter
about 1 year ago
inallhonesty Lead Judge
about 1 year ago
samuraii77 Submitter
about 1 year ago
inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

The skew of a market could go over the maxSkew due to bad assumption in checkOpenInterestLimits (after the fix of "`liquidateAccounts` calls `updateOpenInterest` with 0 OI and skew")

Support

FAQs

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