From 5bed473903213f09e612ea6435f49cf5f87c9417 Mon Sep 17 00:00:00 2001 From: sunce86 Date: Fri, 3 Jan 2025 12:40:58 +0100 Subject: [PATCH 1/5] Initial commit --- crates/model/src/order.rs | 1 + crates/orderbook/src/database/orders.rs | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/crates/model/src/order.rs b/crates/model/src/order.rs index 6aa3e4b78b..42dca7e6b7 100644 --- a/crates/model/src/order.rs +++ b/crates/model/src/order.rs @@ -673,6 +673,7 @@ pub struct OrderMetadata { pub executed_sell_amount: BigUint, #[serde_as(as = "HexOrDecimalU256")] pub executed_sell_amount_before_fees: U256, + // The fee amount is expressed in the surplus token #[serde_as(as = "HexOrDecimalU256")] pub executed_fee_amount: U256, #[serde_as(as = "HexOrDecimalU256")] diff --git a/crates/orderbook/src/database/orders.rs b/crates/orderbook/src/database/orders.rs index 938389b210..50898429b2 100644 --- a/crates/orderbook/src/database/orders.rs +++ b/crates/orderbook/src/database/orders.rs @@ -595,12 +595,24 @@ fn full_order_into_model_order(order: FullOrder) -> Result { // Executed fee amounts and sell amounts before fees are capped by // order's fee and sell amounts, and thus can always fit in a `U256` // - as it is limited by the order format. - executed_sell_amount_before_fees: big_decimal_to_u256(&(order.sum_sell - &order.sum_fee)) - .context( - "executed sell amount before fees does not fit in a u256", - )?, - executed_fee_amount: big_decimal_to_u256(&order.sum_fee) - .context("executed fee amount is not a valid u256")?, + executed_sell_amount_before_fees: big_decimal_to_u256(&(&order.sum_sell - &order.sum_fee)) + .context("executed sell amount before fees does not fit in a u256")?, + executed_fee_amount: { + let fee_in_sell_token = big_decimal_to_u256(&order.sum_fee) + .context("executed fee amount is not a valid u256")?; + match order.kind { + DbOrderKind::Buy => fee_in_sell_token, + DbOrderKind::Sell => { + // convert to buy token using executed amounts which are a very good + // approximation of UCP prices conversion rate + fee_in_sell_token + * big_decimal_to_u256(&order.sum_buy) + .context("executed buy amount is not an unsigned integer")? + / big_decimal_to_u256(&(&order.sum_sell - &order.sum_fee)) + .context("executed sell amount before fees does not fit in a u256")? + } + } + }, executed_surplus_fee: big_decimal_to_u256(&order.executed_fee) .context("executed fee is not a valid u256")?, executed_fee: big_decimal_to_u256(&order.executed_fee) From a036de0d5dd7ac78ef2c30ae9c4f6ee9b8e77902 Mon Sep 17 00:00:00 2001 From: sunce86 Date: Wed, 8 Jan 2025 13:30:17 +0100 Subject: [PATCH 2/5] safe math --- crates/orderbook/openapi.yml | 4 +++- crates/orderbook/src/database/orders.rs | 15 +++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/crates/orderbook/openapi.yml b/crates/orderbook/openapi.yml index aa4c2da3ac..9d654df948 100644 --- a/crates/orderbook/openapi.yml +++ b/crates/orderbook/openapi.yml @@ -902,7 +902,9 @@ components: allOf: - $ref: "#/components/schemas/BigUint" executedFeeAmount: - description: The total amount of fees that have been executed for this order. + description: The total amount of signed order fees that have been executed + for this order. The value is expressed in surplus token - sell token for + buy orders, and in buy token for sell orders. allOf: - $ref: "#/components/schemas/BigUint" invalidated: diff --git a/crates/orderbook/src/database/orders.rs b/crates/orderbook/src/database/orders.rs index 50898429b2..21cbc30854 100644 --- a/crates/orderbook/src/database/orders.rs +++ b/crates/orderbook/src/database/orders.rs @@ -606,10 +606,17 @@ fn full_order_into_model_order(order: FullOrder) -> Result { // convert to buy token using executed amounts which are a very good // approximation of UCP prices conversion rate fee_in_sell_token - * big_decimal_to_u256(&order.sum_buy) - .context("executed buy amount is not an unsigned integer")? - / big_decimal_to_u256(&(&order.sum_sell - &order.sum_fee)) - .context("executed sell amount before fees does not fit in a u256")? + .checked_mul( + big_decimal_to_u256(&order.sum_buy) + .context("executed buy amount is not an unsigned integer")?, + ) + .context("fee_in_sell_token overflow")? + .checked_div( + big_decimal_to_u256(&(&order.sum_sell - &order.sum_fee)).context( + "executed sell amount before fees does not fit in a u256", + )?, + ) + .context("fee_in_sell_token division by zero")? } } }, From 33ddf840110fd42dcd045ab8e8b489477da1dbd9 Mon Sep 17 00:00:00 2001 From: sunce86 Date: Wed, 8 Jan 2025 13:32:31 +0100 Subject: [PATCH 3/5] other place --- crates/shared/src/db_order_conversions.rs | 31 ++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/crates/shared/src/db_order_conversions.rs b/crates/shared/src/db_order_conversions.rs index 44e2ae3320..fe19fc7fe3 100644 --- a/crates/shared/src/db_order_conversions.rs +++ b/crates/shared/src/db_order_conversions.rs @@ -84,12 +84,31 @@ pub fn full_order_into_model_order(order: database::orders::FullOrder) -> Result // Executed fee amounts and sell amounts before fees are capped by // order's fee and sell amounts, and thus can always fit in a `U256` // - as it is limited by the order format. - executed_sell_amount_before_fees: big_decimal_to_u256(&(order.sum_sell - &order.sum_fee)) - .context( - "executed sell amount before fees does not fit in a u256", - )?, - executed_fee_amount: big_decimal_to_u256(&order.sum_fee) - .context("executed fee amount is not a valid u256")?, + executed_sell_amount_before_fees: big_decimal_to_u256(&(&order.sum_sell - &order.sum_fee)) + .context("executed sell amount before fees does not fit in a u256")?, + executed_fee_amount: { + let fee_in_sell_token = big_decimal_to_u256(&order.sum_fee) + .context("executed fee amount is not a valid u256")?; + match order.kind { + DbOrderKind::Buy => fee_in_sell_token, + DbOrderKind::Sell => { + // convert to buy token using executed amounts which are a very good + // approximation of UCP prices conversion rate + fee_in_sell_token + .checked_mul( + big_decimal_to_u256(&order.sum_buy) + .context("executed buy amount is not an unsigned integer")?, + ) + .context("fee_in_sell_token overflow")? + .checked_div( + big_decimal_to_u256(&(&order.sum_sell - &order.sum_fee)).context( + "executed sell amount before fees does not fit in a u256", + )?, + ) + .context("fee_in_sell_token division by zero")? + } + } + }, executed_surplus_fee: big_decimal_to_u256(&order.executed_fee) .context("executed fee is not a valid u256")?, executed_fee: big_decimal_to_u256(&order.executed_fee) From e77a7d73798a621fba1b9c432c39e6c2f5f87645 Mon Sep 17 00:00:00 2001 From: sunce86 Date: Wed, 8 Jan 2025 15:52:11 +0100 Subject: [PATCH 4/5] protect div by zero --- crates/orderbook/src/database/orders.rs | 4 +++- crates/shared/src/db_order_conversions.rs | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/orderbook/src/database/orders.rs b/crates/orderbook/src/database/orders.rs index aa6db48cf4..1fc1567041 100644 --- a/crates/orderbook/src/database/orders.rs +++ b/crates/orderbook/src/database/orders.rs @@ -618,7 +618,9 @@ fn full_order_into_model_order(order: FullOrder) -> Result { // - as it is limited by the order format. executed_sell_amount_before_fees: big_decimal_to_u256(&(&order.sum_sell - &order.sum_fee)) .context("executed sell amount before fees does not fit in a u256")?, - executed_fee_amount: { + executed_fee_amount: if order.sum_fee.is_zero() { + 0.into() + } else { let fee_in_sell_token = big_decimal_to_u256(&order.sum_fee) .context("executed fee amount is not a valid u256")?; match order.kind { diff --git a/crates/shared/src/db_order_conversions.rs b/crates/shared/src/db_order_conversions.rs index fe19fc7fe3..81dcda0a11 100644 --- a/crates/shared/src/db_order_conversions.rs +++ b/crates/shared/src/db_order_conversions.rs @@ -1,6 +1,7 @@ use { anyhow::{Context, Result}, app_data::AppDataHash, + bigdecimal::Zero, database::{ onchain_broadcasted_orders::OnchainOrderPlacementError as DbOnchainOrderPlacementError, orders::{ @@ -86,7 +87,9 @@ pub fn full_order_into_model_order(order: database::orders::FullOrder) -> Result // - as it is limited by the order format. executed_sell_amount_before_fees: big_decimal_to_u256(&(&order.sum_sell - &order.sum_fee)) .context("executed sell amount before fees does not fit in a u256")?, - executed_fee_amount: { + executed_fee_amount: if order.sum_fee.is_zero() { + 0.into() + } else { let fee_in_sell_token = big_decimal_to_u256(&order.sum_fee) .context("executed fee amount is not a valid u256")?; match order.kind { From 6af37c73c5ad82d6ebbb7d42158841700f514865 Mon Sep 17 00:00:00 2001 From: sunce86 Date: Fri, 10 Jan 2025 11:58:11 +0100 Subject: [PATCH 5/5] fix docs --- crates/orderbook/openapi.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/orderbook/openapi.yml b/crates/orderbook/openapi.yml index 9d654df948..3a3fd4d33f 100644 --- a/crates/orderbook/openapi.yml +++ b/crates/orderbook/openapi.yml @@ -903,8 +903,8 @@ components: - $ref: "#/components/schemas/BigUint" executedFeeAmount: description: The total amount of signed order fees that have been executed - for this order. The value is expressed in surplus token - sell token for - buy orders, and in buy token for sell orders. + for this order. The value is expressed in surplus token (sell token for + buy orders, and in buy token for sell orders). allOf: - $ref: "#/components/schemas/BigUint" invalidated: