Skip to content
This repository was archived by the owner on Apr 28, 2022. It is now read-only.

Remove legacy fee #542

Merged
merged 3 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 0 additions & 44 deletions orderbook/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,27 +156,6 @@ paths:
description: Invalid signature
404:
description: Order was not found
/api/v1/tokens/{sellToken}/fee:
get:
description: |
The fee that is charged for placing an order.
The fee is described by a minimum fee - in order to cover the gas costs for onchain settling - and
a feeRatio charged to the users for using the service.
parameters:
- name: sellToken
in: path
required: true
schema:
$ref: "#/components/schemas/Address"
responses:
200:
description: the fee
content:
application/json:
schema:
$ref: "#/components/schemas/LegacyFeeInformation"
404:
description: sellToken non-existent
/api/v1/trades:
get:
summary: Get existing Trades.
Expand Down Expand Up @@ -329,29 +308,6 @@ components:
required:
- expirationDate
- amount
LegacyFeeInformation:
description: |
Provides the information to calculate the fees.
type: object
properties:
expirationDate:
description: |
Expiration date of the offered fee. Order service might not accept
the fee after this expiration date. Encoded as ISO 8601 UTC.
type: string
example: "2020-12-03T18:35:18.814523Z"
minimalFee:
description: Absolute amount of minimal fee charged per order in specified sellToken
$ref: "#/components/schemas/TokenAmount"
feeRatio:
description: The fee ratio charged on a sellAmount. Denoted in basis points
example: 10
type: number
format: int32
required:
- expirationDate
- minimalFee
- feeRatio
OrderType:
description: Is this a buy order or sell order?
type: string
Expand Down
3 changes: 0 additions & 3 deletions orderbook/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ pub fn handle_all_routes(
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone {
let create_order = create_order::create_order(orderbook.clone());
let get_orders = get_orders::get_orders(orderbook.clone());
let legacy_fee_info = get_fee_info::legacy_get_fee_info(fee_calculator.clone());
let fee_info = get_fee_info::get_fee_info(fee_calculator);
let get_order = get_order_by_uid::get_order_by_uid(orderbook.clone());
let get_solvable_orders = get_solvable_orders::get_solvable_orders(orderbook.clone());
Expand All @@ -50,8 +49,6 @@ pub fn handle_all_routes(
.unify()
.or(fee_info.map(|reply| LabelledReply::new(reply, "fee_info")))
.unify()
.or(legacy_fee_info.map(|reply| LabelledReply::new(reply, "legacy_fee_info")))
.unify()
.or(get_order.map(|reply| LabelledReply::new(reply, "get_order")))
.unify()
.or(get_solvable_orders.map(|reply| LabelledReply::new(reply, "get_solvable_orders")))
Expand Down
92 changes: 5 additions & 87 deletions orderbook/src/api/get_fee_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::H160Wrapper;
use anyhow::Result;
use chrono::{DateTime, Utc};
use model::{order::OrderKind, u256_decimal};
use primitive_types::{H160, U256};
use primitive_types::U256;
use serde::{Deserialize, Serialize};
use std::convert::Infallible;
use std::sync::Arc;
Expand Down Expand Up @@ -73,81 +73,22 @@ pub fn get_fee_info(
fee_calculator
.min_fee(
query.sell_token.0,
Some(query.buy_token.0),
Some(query.amount),
Some(query.kind),
query.buy_token.0,
query.amount,
query.kind,
)
.await,
))
}
})
}

// TODO remove legacy fee endpoint once frontend is updated

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct LegacyFeeInfo {
pub expiration_date: DateTime<Utc>,
#[serde(with = "u256_decimal")]
pub minimal_fee: U256,
pub fee_ratio: u32,
}

pub fn legacy_get_fee_info_request() -> impl Filter<Extract = (H160,), Error = Rejection> + Clone {
warp::path!("tokens" / H160Wrapper / "fee")
.and(warp::get())
.map(|token: H160Wrapper| token.0)
}

pub fn legacy_get_fee_info_response(
result: Result<(U256, DateTime<Utc>), MinFeeCalculationError>,
) -> impl Reply {
match result {
Ok((minimal_fee, expiration_date)) => {
let fee_info = LegacyFeeInfo {
expiration_date,
minimal_fee,
fee_ratio: 0u32,
};
Ok(reply::with_status(reply::json(&fee_info), StatusCode::OK))
}
Err(MinFeeCalculationError::NotFound) => Ok(reply::with_status(
super::error("NotFound", "Token was not found"),
StatusCode::NOT_FOUND,
)),
Err(MinFeeCalculationError::UnsupportedToken(token)) => Ok(reply::with_status(
super::error("UnsupportedToken", format!("Token address {:?}", token)),
StatusCode::BAD_REQUEST,
)),
Err(MinFeeCalculationError::Other(err)) => {
tracing::error!(?err, "get_fee error");
Ok(reply::with_status(
super::internal_error(),
StatusCode::INTERNAL_SERVER_ERROR,
))
}
}
}

pub fn legacy_get_fee_info(
fee_calculator: Arc<MinFeeCalculator>,
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone {
legacy_get_fee_info_request().and_then(move |token| {
let fee_calculator = fee_calculator.clone();
async move {
Result::<_, Infallible>::Ok(legacy_get_fee_info_response(
fee_calculator.min_fee(token, None, None, None).await,
))
}
})
}

#[cfg(test)]
mod tests {
use super::*;
use crate::api::response_body;
use chrono::FixedOffset;
use primitive_types::H160;
use warp::test::request;

#[tokio::test]
Expand Down Expand Up @@ -180,27 +121,4 @@ mod tests {
assert_eq!(body.amount, U256::zero());
assert!(body.expiration_date.gt(&chrono::offset::Utc::now()))
}

#[tokio::test]
async fn legacy_get_fee_info_request_ok() {
let filter = legacy_get_fee_info_request();
let token = String::from("0x0000000000000000000000000000000000000001");
let path_string = format!("/tokens/{}/fee", token);
let request = request().path(&path_string).method("GET");
let result = request.filter(&filter).await.unwrap();
assert_eq!(result, H160::from_low_u64_be(1));
}

#[tokio::test]
async fn legacy_get_fee_info_response_() {
let response =
legacy_get_fee_info_response(Ok((U256::zero(), Utc::now() + FixedOffset::east(10))))
.into_response();
assert_eq!(response.status(), StatusCode::OK);
let body = response_body(response).await;
let body: LegacyFeeInfo = serde_json::from_slice(body.as_slice()).unwrap();
assert_eq!(body.minimal_fee, U256::zero());
assert_eq!(body.fee_ratio, 0);
assert!(body.expiration_date.gt(&chrono::offset::Utc::now()))
}
}
116 changes: 53 additions & 63 deletions orderbook/src/database/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ impl MinFeeStoring for Database {
async fn save_fee_measurement(
&self,
sell_token: H160,
buy_token: Option<H160>,
amount: Option<U256>,
kind: Option<OrderKind>,
buy_token: H160,
amount: U256,
kind: OrderKind,
expiry: DateTime<Utc>,
min_fee: U256,
) -> Result<()> {
const QUERY: &str =
"INSERT INTO min_fee_measurements (sell_token, buy_token, amount, order_kind, expiration_timestamp, min_fee) VALUES ($1, $2, $3, $4, $5, $6);";
sqlx::query(QUERY)
.bind(sell_token.as_bytes())
.bind(buy_token.as_ref().map(|t| t.as_bytes()))
.bind(amount.map(|a| u256_to_big_decimal(&a)))
.bind(kind.map(DbOrderKind::from))
.bind(buy_token.as_bytes())
.bind(u256_to_big_decimal(&amount))
.bind(DbOrderKind::from(kind))
.bind(expiry)
.bind(u256_to_big_decimal(&min_fee))
.execute(&self.pool)
Expand All @@ -37,25 +37,25 @@ impl MinFeeStoring for Database {
async fn get_min_fee(
&self,
sell_token: H160,
buy_token: Option<H160>,
amount: Option<U256>,
kind: Option<OrderKind>,
buy_token: H160,
amount: U256,
kind: OrderKind,
min_expiry: DateTime<Utc>,
) -> Result<Option<U256>> {
const QUERY: &str = "\
SELECT MIN(min_fee) FROM min_fee_measurements \
WHERE sell_token = $1 \
AND ($2 IS NULL OR buy_token = $2) \
AND ($3 IS NULL OR amount = $3) \
AND ($4 IS NULL OR order_kind = $4) \
AND buy_token = $2 \
AND amount = $3 \
AND order_kind = $4 \
AND expiration_timestamp >= $5
";

let result: Option<BigDecimal> = sqlx::query_scalar(QUERY)
.bind(sell_token.as_bytes())
.bind(buy_token.as_ref().map(|t| t.as_bytes()))
.bind(amount.map(|a| u256_to_big_decimal(&a)))
.bind(kind.map(DbOrderKind::from))
.bind(buy_token.as_bytes())
.bind(u256_to_big_decimal(&amount))
.bind(DbOrderKind::from(kind))
.bind(min_expiry)
.fetch_one(&self.pool)
.await
Expand Down Expand Up @@ -100,14 +100,21 @@ mod tests {
let token_b = H160::from_low_u64_be(2);

// Save two measurements for token_a
db.save_fee_measurement(token_a, None, None, None, now, 100u32.into())
.await
.unwrap();
db.save_fee_measurement(
token_a,
None,
None,
None,
token_b,
100.into(),
OrderKind::Sell,
now,
100u32.into(),
)
.await
.unwrap();
db.save_fee_measurement(
token_a,
token_b,
100.into(),
OrderKind::Sell,
now + Duration::seconds(60),
200u32.into(),
)
Expand All @@ -117,9 +124,9 @@ mod tests {
// Save one measurement for token_b
db.save_fee_measurement(
token_b,
Some(token_a),
Some(100.into()),
Some(OrderKind::Buy),
token_a,
100.into(),
OrderKind::Buy,
now,
10u32.into(),
)
Expand All @@ -128,69 +135,52 @@ mod tests {

// Token A has readings valid until now and in 30s
assert_eq!(
db.get_min_fee(token_a, None, None, None, now)
db.get_min_fee(token_a, token_b, 100.into(), OrderKind::Sell, now)
.await
.unwrap()
.unwrap(),
100_u32.into()
);
assert_eq!(
db.get_min_fee(token_a, None, None, None, now + Duration::seconds(30))
.await
.unwrap()
.unwrap(),
db.get_min_fee(
token_a,
token_b,
100.into(),
OrderKind::Sell,
now + Duration::seconds(30)
)
.await
.unwrap()
.unwrap(),
200u32.into()
);

// Token B only has readings valid until now
assert_eq!(
db.get_min_fee(token_b, None, None, None, now)
.await
.unwrap()
.unwrap(),
10u32.into()
);
assert_eq!(
db.get_min_fee(token_b, None, None, None, now + Duration::seconds(30))
.await
.unwrap(),
None
);

// Token B has readings for right filters
assert_eq!(
db.get_min_fee(token_b, Some(token_a), None, None, now)
db.get_min_fee(token_b, token_a, 100.into(), OrderKind::Buy, now)
.await
.unwrap()
.unwrap(),
10u32.into()
);
assert_eq!(
db.get_min_fee(token_b, None, Some(100.into()), None, now)
.await
.unwrap()
.unwrap(),
10u32.into()
);
assert_eq!(
db.get_min_fee(token_b, None, None, Some(OrderKind::Buy), now)
.await
.unwrap()
.unwrap(),
10u32.into()
);
assert_eq!(
db.get_min_fee(token_b, None, Some(U256::zero()), None, now)
.await
.unwrap(),
db.get_min_fee(
token_b,
token_a,
100.into(),
OrderKind::Buy,
now + Duration::seconds(30)
)
.await
.unwrap(),
None
);

db.remove_expired_fee_measurements(now + Duration::seconds(120))
.await
.unwrap();
assert_eq!(
db.get_min_fee(token_b, None, None, None, now)
db.get_min_fee(token_b, token_a, 100.into(), OrderKind::Buy, now)
.await
.unwrap(),
None
Expand Down
Loading