From 82a6558ef6c4d0f06238b9cf85b018e41ba81257 Mon Sep 17 00:00:00 2001 From: Mateo Date: Fri, 1 Mar 2024 11:54:10 +0100 Subject: [PATCH 1/3] Do not count "in-market" orders for the order limit #2433 --- crates/e2e/tests/e2e/limit_orders.rs | 92 ++++++++++++ crates/shared/src/order_validation.rs | 198 ++++++++++++++++++-------- 2 files changed, 229 insertions(+), 61 deletions(-) diff --git a/crates/e2e/tests/e2e/limit_orders.rs b/crates/e2e/tests/e2e/limit_orders.rs index 98a7138018..9584dd27d2 100644 --- a/crates/e2e/tests/e2e/limit_orders.rs +++ b/crates/e2e/tests/e2e/limit_orders.rs @@ -1,5 +1,6 @@ use { contracts::ERC20, + driver::domain::eth::NonZeroU256, e2e::{nodes::forked_node::ForkedNodeApi, setup::*, tx}, ethcontract::{prelude::U256, H160}, model::{ @@ -30,6 +31,12 @@ async fn local_node_too_many_limit_orders() { run_test(too_many_limit_orders_test).await; } +#[tokio::test] +#[ignore] +async fn local_node_limit_does_not_apply_to_in_market_orders_test() { + run_test(limit_does_not_apply_to_in_market_orders_test).await; +} + #[tokio::test] #[ignore] async fn local_node_mixed_limit_and_market_orders() { @@ -483,11 +490,96 @@ async fn too_many_limit_orders_test(web3: Web3) { &onchain.contracts().domain_separator, SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), ); + let (status, body) = services.create_order(&order).await.unwrap_err(); assert_eq!(status, 400); assert!(body.contains("TooManyLimitOrders")); } +async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { + let mut onchain = OnchainComponents::deploy(web3.clone()).await; + + let [solver] = onchain.make_solvers(to_wei(1)).await; + let [trader] = onchain.make_accounts(to_wei(1)).await; + let [token_a] = onchain + .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) + .await; + token_a.mint(trader.address(), to_wei(100)).await; + + // Approve GPv2 for trading + tx!( + trader.account(), + token_a.approve(onchain.contracts().allowance, to_wei(101)) + ); + + // Place Orders + let services = Services::new(onchain.contracts()).await; + let solver_endpoint = + colocation::start_baseline_solver(onchain.contracts().weth.address()).await; + colocation::start_driver( + onchain.contracts(), + vec![colocation::SolverEngine { + name: "test_solver".into(), + account: solver, + endpoint: solver_endpoint, + }], + ); + services + .start_api(vec![ + "--max-limit-orders-per-user=1".into(), + "--price-estimation-drivers=test_quoter|http://localhost:11088/test_solver".to_string(), + ]) + .await; + + let quote_request = OrderQuoteRequest { + from: trader.address(), + sell_token: token_a.address(), + buy_token: onchain.contracts().weth.address(), + side: OrderQuoteSide::Sell { + sell_amount: SellAmount::BeforeFee { + value: NonZeroU256::try_from(to_wei(5)).unwrap(), + }, + }, + ..Default::default() + }; + let quote = services.submit_quote("e_request).await.unwrap(); + + let order = OrderCreation { + sell_token: token_a.address(), + sell_amount: quote.quote.sell_amount, + buy_token: onchain.contracts().weth.address(), + buy_amount: quote.quote.buy_amount.saturating_sub(to_wei(1)), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + ); + let order_id = services.create_order(&order).await.unwrap(); + let limit_order = services.get_order(&order_id).await.unwrap(); + assert!(limit_order.metadata.class.is_limit()); + + // Place another "in-market" order in order to check it is not limited + let order = OrderCreation { + sell_token: token_a.address(), + sell_amount: quote.quote.sell_amount, + buy_token: onchain.contracts().weth.address(), + buy_amount: quote.quote.buy_amount.saturating_sub(to_wei(2)), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + ); + assert!(services.create_order(&order).await.is_ok()); +} + async fn forked_mainnet_single_limit_order_test(web3: Web3) { let mut onchain = OnchainComponents::deployed(web3.clone()).await; let forked_node_api = web3.api::>(); diff --git a/crates/shared/src/order_validation.rs b/crates/shared/src/order_validation.rs index 9bf2c8e8a3..dd111144d8 100644 --- a/crates/shared/src/order_validation.rs +++ b/crates/shared/src/order_validation.rs @@ -351,20 +351,14 @@ impl OrderValidator { self } - async fn check_max_limit_orders( - &self, - owner: H160, - class: &OrderClass, - ) -> Result<(), ValidationError> { - if class.is_limit() { - let num_limit_orders = self - .limit_order_counter - .count(owner) - .await - .map_err(ValidationError::Other)?; - if num_limit_orders >= self.max_limit_orders_per_user { - return Err(ValidationError::TooManyLimitOrders); - } + async fn check_max_limit_orders(&self, owner: H160) -> Result<(), ValidationError> { + let num_limit_orders = self + .limit_order_counter + .count(owner) + .await + .map_err(ValidationError::Other)?; + if num_limit_orders >= self.max_limit_orders_per_user { + return Err(ValidationError::TooManyLimitOrders); } Ok(()) } @@ -593,32 +587,6 @@ impl OrderValidating for OrderValidator { additional_gas: app_data.inner.protocol.hooks.gas_limit(), verification, }; - let quote = match class { - OrderClass::Market => { - let fee = Some(data.fee_amount); - let quote = get_quote_and_check_fee( - &*self.quoter, - "e_parameters, - order.quote_id, - fee, - self.market_orders_deprecation_date, - ) - .await?; - Some(quote) - } - OrderClass::Limit => { - let quote = get_quote_and_check_fee( - &*self.quoter, - "e_parameters, - order.quote_id, - None, - self.market_orders_deprecation_date, - ) - .await?; - Some(quote) - } - OrderClass::Liquidity => None, - }; let min_balance = minimum_balance(&data).ok_or(ValidationError::SellAmountOverflow)?; @@ -668,17 +636,26 @@ impl OrderValidating for OrderValidator { }, } - tracing::debug!( - ?uid, - ?order, - ?quote, - "checking if order is outside market price" - ); // Check if we need to re-classify the market order if it is outside the market // price. We consider out-of-price orders as liquidity orders. See // . - let class = match (class, "e) { - (OrderClass::Market, Some(quote)) + let (class, quote) = match class { + // This has to be here in order to keep the previous behaviour + OrderClass::Market => { + let quote = get_quote_and_check_fee( + &*self.quoter, + "e_parameters, + order.quote_id, + Some(data.fee_amount), + self.market_orders_deprecation_date, + ) + .await?; + tracing::debug!( + ?uid, + ?order, + ?quote, + "checking if order is outside market price" + ); if is_order_outside_market_price( &Amounts { sell: data.sell_amount, @@ -690,16 +667,42 @@ impl OrderValidating for OrderValidator { buy: quote.buy_amount, fee: quote.fee_amount, }, - ) => - { - tracing::debug!(%uid, ?owner, ?class, "order being flagged as outside market price"); - OrderClass::Liquidity + ) { + tracing::debug!(%uid, ?owner, ?class, "order being flagged as outside market price"); + (OrderClass::Liquidity, Some(quote)) + } else { + (class, Some(quote)) + } } - (_, _) => class, + OrderClass::Limit => { + let quote = get_quote_and_check_fee( + &*self.quoter, + "e_parameters, + order.quote_id, + None, + self.market_orders_deprecation_date, + ) + .await?; + // If the order is not "In-Market", check for the limit orders + if is_order_outside_market_price( + &Amounts { + sell: data.sell_amount, + buy: data.buy_amount, + fee: data.fee_amount, + }, + &Amounts { + sell: quote.sell_amount, + buy: quote.buy_amount, + fee: quote.fee_amount, + }, + ) { + self.check_max_limit_orders(owner).await?; + } + (class, Some(quote)) + } + OrderClass::Liquidity => (class, None), }; - self.check_max_limit_orders(owner, &class).await?; - let order = Order { metadata: OrderMetadata { owner, @@ -1424,9 +1427,15 @@ mod tests { let mut order_quoter = MockOrderQuoting::new(); let mut bad_token_detector = MockBadTokenDetecting::new(); let mut balance_fetcher = MockBalanceFetching::new(); - order_quoter - .expect_find_quote() - .returning(|_, _| Ok(Default::default())); + order_quoter.expect_find_quote().returning(|_, _| { + Ok(Quote { + id: None, + data: Default::default(), + sell_amount: U256::from(1), + buy_amount: U256::from(1), + fee_amount: Default::default(), + }) + }); bad_token_detector .expect_detect() .returning(|_| Ok(TokenQuality::Good)); @@ -1449,7 +1458,7 @@ mod tests { let validator = OrderValidator::new( dummy_contract!(WETH9, [0xef; 20]), - Arc::new(order_validation::banned::Users::none()), + hashset!(), OrderValidPeriodConfiguration::any(), false, Arc::new(bad_token_detector), @@ -1461,14 +1470,13 @@ mod tests { MAX_LIMIT_ORDERS_PER_USER, Arc::new(MockCodeFetching::new()), Default::default(), - None, ); let creation = OrderCreation { valid_to: model::time::now_in_epoch_seconds() + 2, sell_token: H160::from_low_u64_be(1), buy_token: H160::from_low_u64_be(2), - buy_amount: U256::from(1), + buy_amount: U256::from(10), sell_amount: U256::from(1), signature: Signature::Eip712(EcdsaSignature::non_zero()), app_data: OrderCreationAppData::Full { @@ -1490,6 +1498,74 @@ mod tests { ); } + #[tokio::test] + async fn post_limit_does_not_apply_to_in_market_orders() { + let mut order_quoter = MockOrderQuoting::new(); + let mut bad_token_detector = MockBadTokenDetecting::new(); + let mut balance_fetcher = MockBalanceFetching::new(); + order_quoter + .expect_find_quote() + .returning(|_, _| Ok(Default::default())); + bad_token_detector + .expect_detect() + .returning(|_| Ok(TokenQuality::Good)); + balance_fetcher + .expect_can_transfer() + .returning(|_, _| Ok(())); + + let mut signature_validating = MockSignatureValidating::new(); + signature_validating + .expect_validate_signature_and_get_additional_gas() + .never(); + let signature_validating = Arc::new(signature_validating); + + const MAX_LIMIT_ORDERS_PER_USER: u64 = 2; + + let mut limit_order_counter = MockLimitOrderCounting::new(); + limit_order_counter + .expect_count() + .returning(|_| Ok(MAX_LIMIT_ORDERS_PER_USER)); + + let validator = OrderValidator::new( + dummy_contract!(WETH9, [0xef; 20]), + Arc::new(order_validation::banned::Users::none()), + OrderValidPeriodConfiguration::any(), + false, + Arc::new(bad_token_detector), + dummy_contract!(HooksTrampoline, [0xcf; 20]), + Arc::new(order_quoter), + Arc::new(balance_fetcher), + signature_validating, + Arc::new(limit_order_counter), + MAX_LIMIT_ORDERS_PER_USER, + Arc::new(MockCodeFetching::new()), + Default::default(), + None, + ); + + let creation = OrderCreation { + valid_to: model::time::now_in_epoch_seconds() + 2, + sell_token: H160::from_low_u64_be(1), + buy_token: H160::from_low_u64_be(2), + buy_amount: U256::from(1), + sell_amount: U256::from(1), + signature: Signature::Eip712(EcdsaSignature::non_zero()), + app_data: OrderCreationAppData::Full { + full: "{}".to_string(), + }, + ..Default::default() + }; + assert!(validator + .validate_and_construct_order( + creation.clone(), + &Default::default(), + Default::default(), + None, + ) + .await + .is_ok()); + } + #[tokio::test] async fn post_validate_err_zero_amount() { let mut order_quoter = MockOrderQuoting::new(); From f74923b6a0bc24fe1b0e475815b430de08913f70 Mon Sep 17 00:00:00 2001 From: Mateo Date: Mon, 4 Mar 2024 14:42:51 +0100 Subject: [PATCH 2/3] Calculate in-market based on the stored quote --- crates/database/src/orders.rs | 39 ++++++++++++++++++++++++ crates/e2e/tests/e2e/limit_orders.rs | 40 ++++++++++++++++++++++++- crates/orderbook/src/database/orders.rs | 26 ++++++++++++++-- crates/shared/src/order_validation.rs | 15 ++++++---- 4 files changed, 112 insertions(+), 8 deletions(-) diff --git a/crates/database/src/orders.rs b/crates/database/src/orders.rs index 9167dde027..88b3b55a1f 100644 --- a/crates/database/src/orders.rs +++ b/crates/database/src/orders.rs @@ -716,6 +716,45 @@ pub async fn count_limit_orders_by_owner( .await } +#[derive(Debug, sqlx::FromRow)] +pub struct OrderWithQuote { + pub order_buy_amount: BigDecimal, + pub order_sell_amount: BigDecimal, + pub order_fee_amount: BigDecimal, + pub quote_buy_amount: BigDecimal, + pub quote_sell_amount: BigDecimal, + pub quote_gas_amount: f64, + pub quote_gas_price: f64, + pub quote_sell_token_price: f64, +} + +pub async fn user_orders_with_quote( + ex: &mut PgConnection, + min_valid_to: i64, + owner: &Address, +) -> Result, sqlx::Error> { + #[rustfmt::skip] + 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_quotes.gas_price as quote_gas_price, o_quotes.sell_token_price as quote_sell_token_price", + " FROM order_quotes o_quotes", + " LEFT JOIN (", + " SELECT *", + " FROM (", OPEN_ORDERS, + " AND owner = $2", + " AND class = 'limit'", + " ) AS subquery", + " ) AS o ON o_quotes.order_uid = o.uid" + ); + sqlx::query_as::<_, OrderWithQuote>(QUERY) + .bind(min_valid_to) + .bind(owner) + .fetch_all(ex) + .await +} + #[cfg(test)] mod tests { use { diff --git a/crates/e2e/tests/e2e/limit_orders.rs b/crates/e2e/tests/e2e/limit_orders.rs index 9584dd27d2..477a888eac 100644 --- a/crates/e2e/tests/e2e/limit_orders.rs +++ b/crates/e2e/tests/e2e/limit_orders.rs @@ -544,11 +544,29 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { }; let quote = services.submit_quote("e_request).await.unwrap(); + // Place "in-market" order let order = OrderCreation { sell_token: token_a.address(), sell_amount: quote.quote.sell_amount, buy_token: onchain.contracts().weth.address(), - buy_amount: quote.quote.buy_amount.saturating_sub(to_wei(1)), + buy_amount: quote.quote.buy_amount.saturating_sub(to_wei(4)), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + ); + assert!(services.create_order(&order).await.is_ok()); + + // Place a "limit" order + let order = OrderCreation { + sell_token: token_a.address(), + sell_amount: to_wei(1), + buy_token: onchain.contracts().weth.address(), + buy_amount: to_wei(3), valid_to: model::time::now_in_epoch_seconds() + 300, kind: OrderKind::Sell, ..Default::default() @@ -578,6 +596,26 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), ); assert!(services.create_order(&order).await.is_ok()); + + // Place a "limit" order in order to see if fails + let order = OrderCreation { + sell_token: token_a.address(), + sell_amount: to_wei(1), + buy_token: onchain.contracts().weth.address(), + buy_amount: to_wei(2), + valid_to: model::time::now_in_epoch_seconds() + 300, + kind: OrderKind::Sell, + ..Default::default() + } + .sign( + EcdsaSigningScheme::Eip712, + &onchain.contracts().domain_separator, + SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()), + ); + + let (status, body) = services.create_order(&order).await.unwrap_err(); + assert_eq!(status, 400); + assert!(body.contains("TooManyLimitOrders")); } async fn forked_mainnet_single_limit_order_test(web3: Web3) { diff --git a/crates/orderbook/src/database/orders.rs b/crates/orderbook/src/database/orders.rs index 4e8ebb0c67..a2e0d66183 100644 --- a/crates/orderbook/src/database/orders.rs +++ b/crates/orderbook/src/database/orders.rs @@ -44,8 +44,9 @@ use { signing_scheme_from, signing_scheme_into, }, + fee::FeeParameters, order_quoting::Quote, - order_validation::LimitOrderCounting, + order_validation::{is_order_outside_market_price, Amounts, LimitOrderCounting}, }, sqlx::{types::BigDecimal, Connection, PgConnection}, std::convert::TryInto, @@ -374,12 +375,33 @@ impl LimitOrderCounting for Postgres { .start_timer(); let mut ex = self.pool.acquire().await?; - Ok(database::orders::count_limit_orders_by_owner( + Ok(database::orders::user_orders_with_quote( &mut ex, now_in_epoch_seconds().into(), &ByteArray(owner.0), ) .await? + .into_iter() + .filter(|order_with_quote| { + is_order_outside_market_price( + &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(), + }, + &Amounts { + sell: big_decimal_to_u256(&order_with_quote.quote_sell_amount).unwrap(), + buy: big_decimal_to_u256(&order_with_quote.quote_buy_amount).unwrap(), + fee: FeeParameters { + gas_amount: order_with_quote.quote_gas_amount, + gas_price: order_with_quote.quote_gas_price, + sell_token_price: order_with_quote.quote_sell_token_price, + } + .fee(), + }, + ) + }) + .count() .try_into() .unwrap()) } diff --git a/crates/shared/src/order_validation.rs b/crates/shared/src/order_validation.rs index dd111144d8..14fb082ad6 100644 --- a/crates/shared/src/order_validation.rs +++ b/crates/shared/src/order_validation.rs @@ -669,7 +669,7 @@ impl OrderValidating for OrderValidator { }, ) { tracing::debug!(%uid, ?owner, ?class, "order being flagged as outside market price"); - (OrderClass::Liquidity, Some(quote)) + (OrderClass::Limit, Some(quote)) } else { (class, Some(quote)) } @@ -700,7 +700,7 @@ impl OrderValidating for OrderValidator { } (class, Some(quote)) } - OrderClass::Liquidity => (class, None), + OrderClass::Liquidity => (OrderClass::Limit, None), }; let order = Order { @@ -1458,8 +1458,12 @@ mod tests { let validator = OrderValidator::new( dummy_contract!(WETH9, [0xef; 20]), - hashset!(), - OrderValidPeriodConfiguration::any(), + Arc::new(order_validation::banned::Users::none()), + OrderValidPeriodConfiguration { + min: Duration::from_secs(1), + max_market: Duration::from_secs(100), + max_limit: Duration::from_secs(200), + }, false, Arc::new(bad_token_detector), dummy_contract!(HooksTrampoline, [0xcf; 20]), @@ -1470,6 +1474,7 @@ mod tests { MAX_LIMIT_ORDERS_PER_USER, Arc::new(MockCodeFetching::new()), Default::default(), + None, ); let creation = OrderCreation { @@ -1677,7 +1682,7 @@ mod tests { // Out-of-price orders are intentionally marked as liquidity // orders! - assert_eq!(order.metadata.class, OrderClass::Liquidity); + assert_eq!(order.metadata.class, OrderClass::Limit); assert!(quote.is_some()); } From 10bc0b371391533a0c2de0638010653b1e33b83a Mon Sep 17 00:00:00 2001 From: Mateo Date: Tue, 5 Mar 2024 13:17:37 +0100 Subject: [PATCH 3/3] Check for number of limit orders also for liquidity orders --- crates/e2e/tests/e2e/limit_orders.rs | 16 ++++++++-------- crates/shared/src/order_validation.rs | 27 ++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/crates/e2e/tests/e2e/limit_orders.rs b/crates/e2e/tests/e2e/limit_orders.rs index 477a888eac..0160dc6922 100644 --- a/crates/e2e/tests/e2e/limit_orders.rs +++ b/crates/e2e/tests/e2e/limit_orders.rs @@ -501,15 +501,15 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { let [solver] = onchain.make_solvers(to_wei(1)).await; let [trader] = onchain.make_accounts(to_wei(1)).await; - let [token_a] = onchain + let [token] = onchain .deploy_tokens_with_weth_uni_v2_pools(to_wei(1_000), to_wei(1_000)) .await; - token_a.mint(trader.address(), to_wei(100)).await; + token.mint(trader.address(), to_wei(100)).await; // Approve GPv2 for trading tx!( trader.account(), - token_a.approve(onchain.contracts().allowance, to_wei(101)) + token.approve(onchain.contracts().allowance, to_wei(101)) ); // Place Orders @@ -533,7 +533,7 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { let quote_request = OrderQuoteRequest { from: trader.address(), - sell_token: token_a.address(), + sell_token: token.address(), buy_token: onchain.contracts().weth.address(), side: OrderQuoteSide::Sell { sell_amount: SellAmount::BeforeFee { @@ -546,7 +546,7 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { // Place "in-market" order let order = OrderCreation { - sell_token: token_a.address(), + sell_token: token.address(), sell_amount: quote.quote.sell_amount, buy_token: onchain.contracts().weth.address(), buy_amount: quote.quote.buy_amount.saturating_sub(to_wei(4)), @@ -563,7 +563,7 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { // Place a "limit" order let order = OrderCreation { - sell_token: token_a.address(), + sell_token: token.address(), sell_amount: to_wei(1), buy_token: onchain.contracts().weth.address(), buy_amount: to_wei(3), @@ -582,7 +582,7 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { // Place another "in-market" order in order to check it is not limited let order = OrderCreation { - sell_token: token_a.address(), + sell_token: token.address(), sell_amount: quote.quote.sell_amount, buy_token: onchain.contracts().weth.address(), buy_amount: quote.quote.buy_amount.saturating_sub(to_wei(2)), @@ -599,7 +599,7 @@ async fn limit_does_not_apply_to_in_market_orders_test(web3: Web3) { // Place a "limit" order in order to see if fails let order = OrderCreation { - sell_token: token_a.address(), + sell_token: token.address(), sell_amount: to_wei(1), buy_token: onchain.contracts().weth.address(), buy_amount: to_wei(2), diff --git a/crates/shared/src/order_validation.rs b/crates/shared/src/order_validation.rs index 14fb082ad6..f7939b8b93 100644 --- a/crates/shared/src/order_validation.rs +++ b/crates/shared/src/order_validation.rs @@ -700,7 +700,32 @@ impl OrderValidating for OrderValidator { } (class, Some(quote)) } - OrderClass::Liquidity => (OrderClass::Limit, None), + OrderClass::Liquidity => { + let quote = get_quote_and_check_fee( + &*self.quoter, + "e_parameters, + order.quote_id, + None, + self.market_orders_deprecation_date, + ) + .await?; + // If the order is not "In-Market", check for the limit orders + if is_order_outside_market_price( + &Amounts { + sell: data.sell_amount, + buy: data.buy_amount, + fee: data.fee_amount, + }, + &Amounts { + sell: quote.sell_amount, + buy: quote.buy_amount, + fee: quote.fee_amount, + }, + ) { + self.check_max_limit_orders(owner).await?; + } + (OrderClass::Limit, None) + } }; let order = Order {