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

Higher fees for skew flipping trades will discourage large trades and encourage gaming the system

Summary

Large orders that flip the skew are treated differently from multiple smaller orders that achieve the same net effect, potentially discouraging larger trades.

Vulnerability Details

if (sameSide) {
// charge (typically) lower maker fee when:
// current skew > 0 AND order is sell/short AND current skew != 0
// current skew < 0 AND order is buy/long AND current skew != 0
UD60x18 feeBps = isSkewGtZero != isBuyOrder && !skew.isZero()
? ud60x18(self.configuration.orderFees.makerFee)
: ud60x18(self.configuration.orderFees.takerFee);
// output order fee
orderFeeUsd = markPriceX18.mul(sizeDelta.abs().intoUD60x18()).mul(feeBps);
}
// special logic for trades that flip the skew; trader should receive:
// makerFee for portion of size that returns skew to 0
// takerFee for portion of size that flips skew in other direction
else {
// convert new skew abs(SD59x18) -> uint256
uint256 takerSize = newSkew.abs().intoUint256();
// abs( abs(orderSize) - abs(newSkew) ) -> uint256
uint256 makerSize = sizeDelta.abs().sub(sd59x18(int256(takerSize))).abs().intoUint256();
// calculate corresponding fees for maker and taker portions
// of this trade which flipped the skew
UD60x18 takerFee =
markPriceX18.mul(ud60x18(takerSize)).mul(ud60x18(self.configuration.orderFees.takerFee));
UD60x18 makerFee =
markPriceX18.mul(ud60x18(makerSize)).mul(ud60x18(self.configuration.orderFees.makerFee));
// output order fee
orderFeeUsd = takerFee.add(makerFee);
}

Consider a market with the following conditions:

  • Current skew: +95 (long-heavy)

  • Maker fee: 0.05% (0.0005)

  • Taker fee: 0.1% (0.001)

  • Mark price: $1000

Option 1: Single large order of 200

  • Fee calculation:

    • Maker portion: 95 * $1000 * 0.0005 = $47.5

    • Taker portion: 105 * $1000 * 0.001 = $105

    • Total fee: $47.5 + $105 = $152.5

Option 2: Split the order

  1. First order: Sell 95 units

    • Fee: 95 * $1000 * 0.0005 = $47.5 (maker fee)

  2. Second order: Sell 105 units

    • Fee: 105 * $1000 * 0.001 = $105 (taker fee)

Total fee for split orders: $47.5 + $105 = $152.5

  1. Optimized split:

  • First order: Sell 96 units

    • Fee: 96 * $1000 * 0.0005 = $48 (maker fee)

  • Second order: Sell 104 units

    • Fee: 104 * $1000 * 0.0005 = $52 (now a maker fee because it's reducing skew)

  • Total fee: $48 + $52 = $100

In this optimized split, the trader saves $52.5 in fees by carefully sizing their orders.

https://github.com/Cyfrin/2024-07-zaros/blob/d687fe96bb7ace8652778797052a38763fbcbb1b/src/perpetuals/leaves/PerpMarket.sol#L190C9-L220C10

Impact

The protocol may earn less in fees than intended, as traders optimize their order placement to minimize fees. Sophisticated traders with advanced algorithms can consistently pay lower fees than less sophisticated market participants, creating an unfair playing field.

Tools Used

Manual Review

Recommendations

Not an easy solution but Zaros could consider implementing a more uniform fee structure that doesn't create such stark differences based on order size or market impact. Alternatively, it could implement a sliding scale fee structure based on order size and market impact, making it more difficult to game the system through order splitting.

Updates

Lead Judging Commences

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

Crafted orders that flip skew can optimize fee payment

Appeal created

slavcheww Auditor
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

Crafted orders that flip skew can optimize fee payment

Support

FAQs

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