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

introduce new PriceEstimationError #1188

Merged
merged 6 commits into from
Oct 4, 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
23 changes: 22 additions & 1 deletion orderbook/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use anyhow::Error as anyhowError;
use serde::de::DeserializeOwned;
use serde::Serialize;
use shared::metrics::get_metric_storage_registry;
use shared::price_estimation::PriceEstimating;
use shared::price_estimation::{PriceEstimating, PriceEstimationError};
use std::{convert::Infallible, sync::Arc};
use warp::{
hyper::StatusCode,
Expand Down Expand Up @@ -135,6 +135,27 @@ pub fn convert_get_trades_error_to_reply(err: anyhowError) -> WithStatus<Json> {
with_status(internal_error(), StatusCode::INTERNAL_SERVER_ERROR)
}

pub fn price_estimation_error_to_warp_reply(err: PriceEstimationError) -> (Json, StatusCode) {
match err {
PriceEstimationError::UnsupportedToken(token) => (
error("UnsupportedToken", format!("Token address {:?}", token)),
StatusCode::BAD_REQUEST,
),
PriceEstimationError::NoLiquidity => (
error("NoLiquidity", "not enough liquidity"),
StatusCode::NOT_FOUND,
),
PriceEstimationError::ZeroAmount => (
error("ZeroAmount", "Please use non-zero amount field"),
StatusCode::BAD_REQUEST,
),
PriceEstimationError::Other(err) => {
tracing::error!(?err, "get_market error");
(internal_error(), StatusCode::INTERNAL_SERVER_ERROR)
}
}
}

#[cfg(test)]
async fn response_body(response: warp::hyper::Response<warp::hyper::Body>) -> Vec<u8> {
let mut body = response.into_body();
Expand Down
63 changes: 20 additions & 43 deletions orderbook/src/api/get_fee_and_quote.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::fee::MinFeeCalculating;
use crate::{api::price_estimation_error_to_warp_reply, fee::MinFeeCalculating};
use anyhow::{anyhow, Result};
use chrono::{DateTime, Utc};
use ethcontract::{H160, U256};
Expand Down Expand Up @@ -65,21 +65,8 @@ struct BuyResponse {

#[derive(Debug)]
enum Error {
NoLiquidity,
UnsupportedToken(H160),
AmountIsZero,
SellAmountDoesNotCoverFee,
Other(anyhow::Error),
}

impl From<PriceEstimationError> for Error {
fn from(other: PriceEstimationError) -> Self {
match other {
PriceEstimationError::NoLiquidity => Error::NoLiquidity,
PriceEstimationError::UnsupportedToken(token) => Error::UnsupportedToken(token),
PriceEstimationError::Other(error) => Error::Other(error),
}
}
PriceEstimate(PriceEstimationError),
}

async fn calculate_sell(
Expand All @@ -88,7 +75,7 @@ async fn calculate_sell(
query: SellQuery,
) -> Result<SellResponse, Error> {
if query.sell_amount_before_fee.is_zero() {
return Err(Error::AmountIsZero);
return Err(Error::PriceEstimate(PriceEstimationError::ZeroAmount));
}

// TODO: would be nice to use true sell amount after the fee but that is more complicated.
Expand All @@ -99,7 +86,8 @@ async fn calculate_sell(
Some(query.sell_amount_before_fee),
Some(OrderKind::Sell),
)
.await?;
.await
.map_err(Error::PriceEstimate)?;
let sell_amount_after_fee = query
.sell_amount_before_fee
.checked_sub(fee)
Expand All @@ -113,7 +101,8 @@ async fn calculate_sell(
in_amount: sell_amount_after_fee,
kind: OrderKind::Sell,
})
.await?;
.await
.map_err(Error::PriceEstimate)?;

Ok(SellResponse {
fee: Fee {
Expand All @@ -130,7 +119,7 @@ async fn calculate_buy(
query: BuyQuery,
) -> Result<BuyResponse, Error> {
if query.buy_amount_after_fee.is_zero() {
return Err(Error::AmountIsZero);
return Err(Error::PriceEstimate(PriceEstimationError::ZeroAmount));
}

let (fee, expiration_date) = fee_calculator
Expand All @@ -140,7 +129,8 @@ async fn calculate_buy(
Some(query.buy_amount_after_fee),
Some(OrderKind::Buy),
)
.await?;
.await
.map_err(Error::PriceEstimate)?;

let estimate = price_estimator
.estimate(&price_estimation::Query {
Expand All @@ -149,11 +139,13 @@ async fn calculate_buy(
in_amount: query.buy_amount_after_fee,
kind: OrderKind::Buy,
})
.await?;
let sell_amount_before_fee = estimate
.out_amount
.checked_add(fee)
.ok_or_else(|| Error::Other(anyhow!("overflow in sell_amount_before_fee")))?;
.await
.map_err(Error::PriceEstimate)?;
let sell_amount_before_fee = estimate.out_amount.checked_add(fee).ok_or_else(|| {
Error::PriceEstimate(PriceEstimationError::Other(anyhow!(
"overflow in sell_amount_before_fee"
)))
})?;

Ok(BuyResponse {
fee: Fee {
Expand All @@ -179,31 +171,16 @@ fn buy_request() -> impl Filter<Extract = (BuyQuery,), Error = Rejection> + Clon
fn response<T: Serialize>(result: Result<T, Error>) -> impl Reply {
match result {
Ok(response) => reply::with_status(reply::json(&response), StatusCode::OK),
Err(Error::NoLiquidity) => reply::with_status(
super::error("NoLiquidity", "not enough liquidity"),
StatusCode::NOT_FOUND,
),
Err(Error::UnsupportedToken(token)) => reply::with_status(
super::error("UnsupportedToken", format!("Token address {:?}", token)),
StatusCode::BAD_REQUEST,
),
Err(Error::AmountIsZero) => reply::with_status(
super::error(
"AmountIsZero",
"The input amount must be greater than zero.".to_string(),
),
StatusCode::BAD_REQUEST,
),
Err(Error::SellAmountDoesNotCoverFee) => reply::with_status(
super::error(
"SellAmountDoesNotCoverFee",
"The sell amount for the sell order is lower than the fee.".to_string(),
),
StatusCode::BAD_REQUEST,
),
Err(Error::Other(err)) => {
tracing::error!(?err, "get_fee_and_price error");
reply::with_status(super::internal_error(), StatusCode::INTERNAL_SERVER_ERROR)
Err(Error::PriceEstimate(err)) => {
let (json, status_code) = price_estimation_error_to_warp_reply(err);
reply::with_status(json, status_code)
}
}
}
Expand Down
35 changes: 7 additions & 28 deletions orderbook/src/api/get_fee_info.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::api::price_estimation_error_to_warp_reply;
use crate::fee::{EthAwareMinFeeCalculator, MinFeeCalculating};
use anyhow::Result;
use chrono::{DateTime, Utc};
Expand Down Expand Up @@ -44,20 +45,9 @@ pub fn get_fee_info_response(
};
Ok(reply::with_status(reply::json(&fee_info), StatusCode::OK))
}
Err(PriceEstimationError::NoLiquidity) => Ok(reply::with_status(
super::error("NoLiquidity", "not enough liquidity"),
StatusCode::NOT_FOUND,
)),
Err(PriceEstimationError::UnsupportedToken(token)) => Ok(reply::with_status(
super::error("UnsupportedToken", format!("Token address {:?}", token)),
StatusCode::BAD_REQUEST,
)),
Err(PriceEstimationError::Other(err)) => {
tracing::error!(?err, "get_fee error");
Ok(reply::with_status(
super::internal_error(),
StatusCode::INTERNAL_SERVER_ERROR,
))
Err(err) => {
let (json, status_code) = price_estimation_error_to_warp_reply(err);
Ok(reply::with_status(json, status_code))
}
}
}
Expand Down Expand Up @@ -111,20 +101,9 @@ pub fn legacy_get_fee_info_response(
};
Ok(reply::with_status(reply::json(&fee_info), StatusCode::OK))
}
Err(PriceEstimationError::NoLiquidity) => Ok(reply::with_status(
super::error("NoLiquidity", "not enough liquidity"),
StatusCode::NOT_FOUND,
)),
Err(PriceEstimationError::UnsupportedToken(token)) => Ok(reply::with_status(
super::error("UnsupportedToken", format!("Token address {:?}", token)),
StatusCode::BAD_REQUEST,
)),
Err(PriceEstimationError::Other(err)) => {
tracing::error!(?err, "get_fee error");
Ok(reply::with_status(
super::internal_error(),
StatusCode::INTERNAL_SERVER_ERROR,
))
Err(err) => {
let (json, status_code) = price_estimation_error_to_warp_reply(err);
Ok(reply::with_status(json, status_code))
}
}
}
Expand Down
15 changes: 4 additions & 11 deletions orderbook/src/api/get_markets.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::api::price_estimation_error_to_warp_reply;
use anyhow::{anyhow, Result};
use ethcontract::{H160, U256};
use model::order::OrderKind;
Expand Down Expand Up @@ -78,17 +79,9 @@ fn get_amount_estimate_response(
}),
StatusCode::OK,
),
Err(PriceEstimationError::UnsupportedToken(token)) => reply::with_status(
super::error("UnsupportedToken", format!("Token address {:?}", token)),
StatusCode::BAD_REQUEST,
),
Err(PriceEstimationError::NoLiquidity) => reply::with_status(
super::error("NoLiquidity", "not enough liquidity"),
StatusCode::NOT_FOUND,
),
Err(PriceEstimationError::Other(err)) => {
tracing::error!(?err, "get_market error");
reply::with_status(super::internal_error(), StatusCode::INTERNAL_SERVER_ERROR)
Err(err) => {
let (json, status_code) = price_estimation_error_to_warp_reply(err);
reply::with_status(json, status_code)
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions shared/src/price_estimation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ pub enum PriceEstimationError {
#[error("No liquidity")]
NoLiquidity,

#[error("Zero Amount")]
ZeroAmount,

#[error(transparent)]
Other(#[from] anyhow::Error),
}
Expand All @@ -35,6 +38,7 @@ impl Clone for PriceEstimationError {
match self {
Self::UnsupportedToken(token) => Self::UnsupportedToken(*token),
Self::NoLiquidity => Self::NoLiquidity,
Self::ZeroAmount => Self::ZeroAmount,
Self::Other(err) => Self::Other(crate::clone_anyhow_error(err)),
}
}
Expand Down