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

Inconsistent Fill Price Validation for Offchain Orders

Summary

There is a critical logic issue when filling Offchain orders.

The inconsistent validation of fill prices (ctx.fillPriceX18) against target prices (ctx.offchainOrder.targetPrice) can lead to orders being incorrectly accepted or rejected.

https://github.com/Cyfrin/2024-07-zaros/blob/d687fe96bb7ace8652778797052a38763fbcbb1b/src/perpetuals/branches/SettlementBranch.sol#L283C13-L287C105

// if the order increases the trading account's position (buy order), the fill price must be less than or
// equal to the target price, if it decreases the trading account's position (sell order), the fill price
// must be greater than or equal to the target price.
ctx.isFillPriceValid = (ctx.isBuyOrder && ctx.offchainOrder.targetPrice <= ctx.fillPriceX18.intoUint256())
|| (!ctx.isBuyOrder && ctx.offchainOrder.targetPrice >= ctx.fillPriceX18.intoUint256());

Notice that the documentation is correct:

  • if the order increases the trading account's position (buy order), the fill price must be less than or equal to the target price

  • if it decreases the trading account's position (sell order), the fill price must be greater than or equal to the target price.

But the logic is performing the opposite.

  • buyOrder: targetPrice <= ctx.fillPrice

  • sellOrder: targetPrice >= ctx.fillPrice

This incorrect logic leads to two critical scenarios:

Incorrectly Accepted Offers

  • Buy Order:

    • Happy Bob places a buy order with a targetPrice of $100.

    • Due to the flawed logic, the order is accepted even if the fillPriceX18 is $125.

    • Sad Bob ends up buying at $125 instead of $100, resulting in an unintended higher cost.

  • Sell Order:

    • Happy Bob places a sell order with a targetPrice of $100.

    • Due to the flawed logic, the order is accepted even if the fillPriceX18 is $70.

    • Sad Bob ends up selling at $70 instead of $100, resulting in an unintended lower revenue.

Incorrectly Rejected Orders

  • For Buy Orders: Orders might be rejected even if the fillPriceX18 is lower than or equal to the targetPrice. This prevents users from executing potentially profitable trades.

  • For Sell Orders: Orders might be rejected even if the fillPriceX18 is higher than or equal to the targetPrice. This prevents users from executing potentially profitable trades.

Impact

  • Financial Loss: Users might incur losses due to buying at higher prices or selling at lower prices than intended.

  • Missed Opportunities: Users might miss out on favorable trading opportunities if valid orders are incorrectly rejected.

  • Reduced Trust: The Protocol is unfair to users.

Tools Used

Manual Review

Recommendations

Adjust the logic to correctly check the fillPriceX18 against the targetPrice for both buy and sell orders.

- ctx.isFillPriceValid = (ctx.isBuyOrder && ctx.offchainOrder.targetPrice <= ctx.fillPriceX18.intoUint256())
- || (!ctx.isBuyOrder && ctx.offchainOrder.targetPrice >= ctx.fillPriceX18.intoUint256());
+ ctx.isFillPriceValid = (ctx.isBuyOrder && ctx.offchainOrder.targetPrice >= ctx.fillPriceX18.intoUint256())
+ || (!ctx.isBuyOrder && ctx.offchainOrder.targetPrice <= ctx.fillPriceX18.intoUint256());
Updates

Lead Judging Commences

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

fillOffchainOrders inverses the comparison between `fillPrice` and `targetPrice`

Support

FAQs

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