Asymmetric fee structure allows market participants to get the same outcome for less fee
| Title | Asymmetric fee structure allows market participants to get the same outcome for less fee |
|---|---|
| Reward | $5492, Unique |
| Contest | Index Fun Order Book - 14 Oct 2025 on Sherlock |
| Author | PUSH0 |
| Context | Swap fees |
When matching an order using swapping (either by matching two users or matching a user versus a market maker), a trade fee is charged. This fee is taken from the collateral amount traded.
We show that, for the same desired outcome, there are two trade paths leading to it, and the fee structure between them is asymmetric: one path charges less.
// Calculate trade fee from user (buyer)
uint256 buyerFeeRate = _getEffectiveTradeFeeRate(order.user);
uint256 tradeFee = (paymentAmount * buyerFeeRate) / 10000;
uint256 netPayment = paymentAmount - tradeFee;
// @audit code example for `_executeAgainstMatcher()`, buy order only. Sell order and matching two orders have the same fee structure
The fee charged is different depending on the trade direction:
- Selling 1000 YES for $300 earns the treasury $3
- Buying 1000 NO for $700 earns the treasury $7
However, this by itself is not necessarily an issue. It could be a ...
But PUSH0 found that in this codebase it is possible to achieve the outcome of selling YES tokens while paying a smaller fee, and to abuse that.
Initial State
Let's say the price becomes 1 YES = 0.92 USDC. Assuming we are already holding 1000 YES, and we want to exit position (sell it). Let trade fee = 2% and claim fee = 1%:
Path 1
Selling 1000 YES gives raw proceeds of 920 USDC. 901.6 goes to the user and 18.4 USDC goes to the treasury as fee.
Path 2
Buying 1000 NO gives raw proceeds of 80 USDC to the market maker. An extra 1.6327 USDC goes to the treasury as fee, and 80 USDC goes to the maker. We spent 81.6327 USDC, but we now hold 1000 YES and 1000 NO.
1000 YES and 1000 NO always redeem to 1000 USDC of collateral. Deduct a 1% claim fee and that makes 990 USDC claimed. Minus the 81.6327 spent on the order, we have a net total of 908.3673 USDC, more than the 901.6 in path 1.
Conclusion
These types of issues are generally unique findings, or have few duplicates, because they are hard to come up with: they require a real understanding of the business logic. In this case, the redemption path available enabled the issue to be weaponized into selling 1000 YES tokens, a certain desired outcome, for less fees.
It is judged medium severity because the loss is bounded (the fee difference is unlikely to exceed 1%) and the market needs to close for the attacker to profit.