Skip to content

Conversation

@squadgazzz
Copy link
Contributor

@squadgazzz squadgazzz commented Nov 11, 2025

Description

Adds protocol volume fee support to the orderbook quote API in order to reflect the auction fees after submitting an order using the same quote. The quote response now includes protocolFeeBps and protocolFeeSellAmount fields when volume fees are configured, allowing users to see the fee before placing orders.

Volume fees are applied to the surplus token (buy token for sell orders, sell token for buy orders) following the same logic as the driver. The orderbook adjusts quote amounts so that orders can be signed with amounts that will be fillable after the driver applies fees during auction competition.

The PriceImprovement and Surplus fees are based on the quotes, so it doesn't make any sense to support them in the quote API.

Changes

  • Added --volume-fee CLI argument to orderbook (e.g., --volume-fee=0.0002 for 0.02% or 2 basis points)
  • Accepts decimal values in range [0, 1) representing the fee factor
  • Added optional protocolFeeBps (string) and protocolFeeSellAmount (U256) fields to OrderQuoteResponse
  • The fields are only present when --volume-fee is configured in the orderbook

Implementation details

  • Volume fee calculation follows driver logic:
    /// Computes the volume based fee in surplus token
    ///
    /// The volume is defined as a full sell amount (including fees) for buy
    /// order, or a full buy amount for sell order.
    fn fee_from_volume(
    &self,
    prices: ClearingPrices,
    factor: f64,
    ) -> Result<eth::TokenAmount, Error> {
    let volume = match self.order().side {
    Side::Buy => self.sell_amount(&prices)?,
    Side::Sell => self.buy_amount(&prices)?,
    };
    volume
    .apply_factor(factor)
    .ok_or(Math::Overflow)
    .map_err(Into::into)
    }
  • Sell orders: Fee calculated on buy_amount, reduces the buy amount returned in quote
  • Buy orders: Fee calculated on sell_amount + network fee, increases the sell amount returned in quote
  • Fee amounts are always converted to sell token for the protocolFeeSellAmount field
  • Uses quote.sell_amount/buy_amount (final computed amounts after network fees) rather than
    quote.data.quoted_sell_amount/quoted_buy_amount (original exchange rate amounts)

How to test

New unit and e2e tests.

Further configuration

This feature needs to be enabled only on a specific block. This logic will be implemented in a follow-up PR.

@github-actions
Copy link

Reminder: Please consider backward compatibility when modifying the API specification.
If breaking changes are unavoidable, ensure:

  • You explicitly pointed out breaking changes.
  • You communicate the changes to affected teams (at least Frontend team and SAFE team).
  • You provide proper versioning and migration mechanisms.

Caused by:

@squadgazzz squadgazzz marked this pull request as ready for review November 11, 2025 19:38
@squadgazzz squadgazzz requested a review from a team as a code owner November 11, 2025 19:38
Copilot AI review requested due to automatic review settings November 11, 2025 19:38
Copilot finished reviewing on behalf of squadgazzz November 11, 2025 19:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds volume-based protocol fee support to the orderbook's quote API, allowing users to see auction fees before submitting orders. The implementation follows the driver's fee calculation logic to ensure quotes remain fillable after fees are applied during auction competition.

Key changes:

  • Added --volume-fee CLI argument accepting decimal values in range [0, 1) representing the fee factor
  • Extended OrderQuoteResponse with optional protocolFeeBps and protocolFeeSellAmount fields
  • Implemented fee calculation logic that adjusts quote amounts based on order side (reduces buy amount for sell orders, increases sell amount for buy orders)

Reviewed Changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
crates/orderbook/src/arguments.rs Adds FeeFactor type and --volume-fee CLI argument with validation
crates/orderbook/src/run.rs Passes volume fee configuration to QuoteHandler
crates/orderbook/src/quoter.rs Implements fee calculation logic and quote adjustment with comprehensive unit tests
crates/orderbook/src/api/post_quote.rs Updates test to include new protocol fee fields
crates/orderbook/openapi.yml Documents new API response fields for protocol fees
crates/model/src/quote.rs Adds optional protocol fee fields to OrderQuoteResponse model
crates/e2e/tests/e2e/quoting.rs Adds end-to-end test validating volume fee behavior for both sell and buy orders
crates/orderbook/Cargo.toml Adds derive_more dependency for Into trait
Cargo.lock Updates lock file with derive_more dependency

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@m-sz m-sz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, small nit.

Comment on lines +375 to +381
let test_cases = vec![
(0.0001, "1"), // 0.01% = 1 bps
(0.001, "10"), // 0.1% = 10 bps
(0.01, "100"), // 1% = 100 bps
(0.05, "500"), // 5% = 500 bps
(0.1, "1000"), // 10% = 1000 bps
];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The comments could be put as 3rd element in the tuple and used as custom assert string on line 395, which would include message on the exact test case that has failed if it ever does.

I know it's a simple code change so I don't insist on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this assertion fails, it will show the expected bps, so there is no need for a detailed error message.

assert_eq!(result.protocol_fee_bps, Some(expected_bps.to_string()));

@squadgazzz squadgazzz requested a review from fafk November 14, 2025 08:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants