Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix quote fee handling in market price #2572

Merged
merged 15 commits into from
Mar 29, 2024
2 changes: 1 addition & 1 deletion crates/autopilot/src/domain/fee/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl ProtocolFees {
.iter()
// TODO: support multiple fee policies
.find_map(|fee_policy| {
let outside_market_price = boundary::is_order_outside_market_price(&order_, &quote_);
let outside_market_price = boundary::is_order_outside_market_price(&order_, &quote_, order.data.kind);
match (outside_market_price, &fee_policy.order_class) {
(_, OrderClass::Any) => Some(&fee_policy.policy),
(true, OrderClass::Limit) => Some(&fee_policy.policy),
Expand Down
4 changes: 2 additions & 2 deletions crates/database/src/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ pub async fn count_limit_orders_by_owner(
pub struct OrderWithQuote {
pub order_buy_amount: BigDecimal,
pub order_sell_amount: BigDecimal,
pub order_fee_amount: BigDecimal,
pub order_kind: OrderKind,
pub quote_buy_amount: BigDecimal,
pub quote_sell_amount: BigDecimal,
pub quote_gas_amount: f64,
Expand All @@ -737,7 +737,7 @@ pub async fn user_orders_with_quote(
const QUERY: &str = const_format::concatcp!(
"SELECT o_quotes.sell_amount as quote_sell_amount, o.sell_amount as order_sell_amount,",
" o_quotes.buy_amount as quote_buy_amount, o.buy_amount as order_buy_amount,",
" o.fee_amount as order_fee_amount, o_quotes.gas_amount as quote_gas_amount,",
" o.kind as order_kind, o_quotes.gas_amount as quote_gas_amount,",
" o_quotes.gas_price as quote_gas_price, o_quotes.sell_token_price as quote_sell_token_price",
" FROM (",
" SELECT *",
Expand Down
25 changes: 14 additions & 11 deletions crates/driver/src/domain/competition/solution/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,18 +225,16 @@ pub struct Quote {
/// - test_adjust_quote_to_in_market_sell_order_limits
/// - test_adjust_quote_to_in_market_buy_order_limits
pub fn adjust_quote_to_order_limits(order: Order, quote: Quote) -> Result<PriceLimits, Math> {
let quote_sell_amount = quote
.sell_amount
.checked_add(quote.fee_amount)
.ok_or(Math::Overflow)?;

match order.side {
Side::Sell => {
let scaled_buy_amount = quote
let quote_buy_amount = quote
.buy_amount
.checked_sub(quote.fee_amount * quote.buy_amount / quote.sell_amount)
sunce86 marked this conversation as resolved.
Show resolved Hide resolved
.ok_or(Math::Negative)?;
let scaled_buy_amount = quote_buy_amount
.checked_mul(order.sell_amount)
.ok_or(Math::Overflow)?
.checked_div(quote_sell_amount)
.checked_div(quote.sell_amount)
.ok_or(Math::DivisionByZero)?;
let buy_amount = order.buy_amount.max(scaled_buy_amount);
Ok(PriceLimits {
Expand All @@ -245,6 +243,10 @@ pub fn adjust_quote_to_order_limits(order: Order, quote: Quote) -> Result<PriceL
})
}
Side::Buy => {
let quote_sell_amount = quote
.sell_amount
.checked_add(quote.fee_amount)
.ok_or(Math::Overflow)?;
let scaled_sell_amount = quote_sell_amount
.checked_mul(order.buy_amount)
.ok_or(Math::Overflow)?
Expand Down Expand Up @@ -325,7 +327,7 @@ mod tests {
side: Side::Sell,
};
let quote = Quote {
sell_amount: to_wei(9),
sell_amount: to_wei(10),
buy_amount: to_wei(25),
fee_amount: to_wei(1),
};
Expand All @@ -336,9 +338,10 @@ mod tests {
limit.sell.0, order.sell_amount,
"Sell amount should be taken from the order for sell orders in market price."
);
assert_eq!(
limit.buy.0, quote.buy_amount,
"Buy amount should reflect the improved market condition from the quote."
assert!(
limit.buy.0 <= quote.buy_amount,
sunce86 marked this conversation as resolved.
Show resolved Hide resolved
"Buy amount should be equal to quoted buy amount if fee is 0, otherwise have to be \
lower."
);
}

Expand Down
6 changes: 5 additions & 1 deletion crates/orderbook/src/database/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ impl LimitOrderCounting for Postgres {
&Amounts {
sell: big_decimal_to_u256(&order_with_quote.order_sell_amount).unwrap(),
buy: big_decimal_to_u256(&order_with_quote.order_buy_amount).unwrap(),
fee: big_decimal_to_u256(&order_with_quote.order_fee_amount).unwrap(),
fee: 0.into(),
},
&Amounts {
sell: big_decimal_to_u256(&order_with_quote.quote_sell_amount).unwrap(),
Expand All @@ -391,6 +391,10 @@ impl LimitOrderCounting for Postgres {
}
.fee(),
},
match order_with_quote.order_kind {
DbOrderKind::Buy => model::order::OrderKind::Buy,
DbOrderKind::Sell => model::order::OrderKind::Sell,
},
)
})
.count()
Expand Down
24 changes: 22 additions & 2 deletions crates/shared/src/order_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ impl OrderValidating for OrderValidator {
buy: quote.buy_amount,
fee: quote.fee_amount,
},
data.kind,
) {
tracing::debug!(%uid, ?owner, ?class, "order being flagged as outside market price");
(OrderClass::Limit, Some(quote))
Expand Down Expand Up @@ -695,6 +696,7 @@ impl OrderValidating for OrderValidator {
buy: quote.buy_amount,
fee: quote.fee_amount,
},
data.kind,
) {
self.check_max_limit_orders(owner).await?;
}
Expand All @@ -721,6 +723,7 @@ impl OrderValidating for OrderValidator {
buy: quote.buy_amount,
fee: quote.fee_amount,
},
data.kind,
) {
self.check_max_limit_orders(owner).await?;
}
Expand Down Expand Up @@ -928,8 +931,22 @@ pub struct Amounts {
///
/// Note that this check only looks at the order's limit price and the market
/// price and is independent of amounts or trade direction.
pub fn is_order_outside_market_price(order: &Amounts, quote: &Amounts) -> bool {
(order.sell + order.fee).full_mul(quote.buy) < (quote.sell + quote.fee).full_mul(order.buy)
pub fn is_order_outside_market_price(
order: &Amounts,
quote: &Amounts,
kind: model::order::OrderKind,
) -> bool {
match kind {
OrderKind::Buy => {
order.sell.full_mul(quote.buy) < (quote.sell + quote.fee).full_mul(order.buy)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Buy order stayed the same as before, as we do need to add fee to sell amount in this case

}
OrderKind::Sell => {
order
.sell
.full_mul(quote.buy - quote.fee * quote.buy / quote.sell)
sunce86 marked this conversation as resolved.
Show resolved Hide resolved
< quote.sell.full_mul(order.buy)
Copy link
Contributor Author

@sunce86 sunce86 Mar 28, 2024

Choose a reason for hiding this comment

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

For buy sell orders, we need to reduce the quote buy amount by converted fee amount

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess you mean "sell" orders here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@harisang Exactly, fixed the comment

}
}
sunce86 marked this conversation as resolved.
Show resolved Hide resolved
}

pub fn convert_signing_scheme_into_quote_signing_scheme(
Expand Down Expand Up @@ -2359,6 +2376,7 @@ mod tests {
buy: quote.buy_amount,
fee: quote.fee_amount,
},
model::order::OrderKind::Buy,
));
// willing to buy less than market price
assert!(!is_order_outside_market_price(
Expand All @@ -2372,6 +2390,7 @@ mod tests {
buy: quote.buy_amount,
fee: quote.fee_amount,
},
model::order::OrderKind::Buy,
));
// wanting to buy more than market price
assert!(is_order_outside_market_price(
Expand All @@ -2385,6 +2404,7 @@ mod tests {
buy: quote.buy_amount,
fee: quote.fee_amount,
},
model::order::OrderKind::Buy,
));
}
}
Loading