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

Check if limit price is respected #88

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
6 changes: 6 additions & 0 deletions src/domain/auction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ impl Price {
}
}

impl From<Price> for U256 {
fn from(value: Price) -> Self {
value.0 .0
}
}

/// The estimated effective gas price that will likely be used for executing the
/// settlement transaction.
#[derive(Clone, Copy, Debug)]
Expand Down
94 changes: 93 additions & 1 deletion src/domain/solution.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
use {
crate::{
domain::{auction, eth, liquidity, order},
domain::{
auction,
eth::{self, TokenAddress},
liquidity,
order::{self, Side},
},
util,
},
ethereum_types::{Address, U256},
shared::conversions::U256Ext,
std::{collections::HashMap, slice},
};

Expand Down Expand Up @@ -232,6 +238,80 @@ pub struct Fulfillment {
fee: Fee,
}

impl Trade {
fn side(&self) -> Side {
match self {
Trade::Fulfillment(fulfillment) => fulfillment.order.side,
Trade::Jit(jit) => jit.order.side,
}
}

fn executed(&self) -> U256 {
match self {
Trade::Fulfillment(fulfillment) => fulfillment.executed,
Trade::Jit(jit) => jit.executed,
}
}

fn fee(&self) -> U256 {
match self {
Trade::Fulfillment(fulfillment) => fulfillment
.surplus_fee()
.map(|surplus| surplus.amount)
.unwrap_or(U256::zero()),
Trade::Jit(_) => U256::zero(),
}
}

/// Returns the trade sell token
pub fn sell_token(&self) -> TokenAddress {
match self {
Trade::Fulfillment(fulfillment) => fulfillment.order.sell.token,
Trade::Jit(jit) => jit.order.sell.token,
}
}

/// Returns the trade buy token
pub fn buy_token(&self) -> TokenAddress {
match self {
Trade::Fulfillment(fulfillment) => fulfillment.order.buy.token,
Trade::Jit(jit) => jit.order.sell.token,
}
}

/// The effective amount that left the user's wallet including all fees.
pub fn sell_amount(&self, sell_price: U256, buy_price: U256) -> Result<U256, error::Math> {
let before_fee = match self.side() {
Side::Sell => self.executed(),
Side::Buy => self
.executed()
.checked_mul(buy_price)
.ok_or(error::Math::Overflow)?
.checked_div(sell_price)
.ok_or(error::Math::DivisionByZero)?,
};
before_fee
.checked_add(self.fee())
.ok_or(error::Math::Overflow)
}

/// The effective amount the user received after all fees.
///
/// Settlement contract uses `ceil` division for buy amount calculation.
pub fn buy_amount(&self, sell_price: U256, buy_price: U256) -> Result<U256, error::Math> {
let amount = match self.side() {
Side::Buy => self.executed(),
Side::Sell => self
.executed()
.checked_mul(sell_price)
.ok_or(error::Math::Overflow)?
.checked_ceil_div(&buy_price)
.ok_or(error::Math::DivisionByZero)?,
};
Ok(amount)
}
}

impl Fulfillment {
/// Creates a new order filled to the specified amount. Returns `None` if
/// the fill amount is incompatible with the order.
Expand Down Expand Up @@ -297,6 +377,18 @@ impl Fulfillment {
}
}

pub mod error {
#[derive(Debug, thiserror::Error)]
pub enum Math {
#[error("overflow")]
Overflow,
#[error("division by zero")]
DivisionByZero,
#[error("negative")]
Negative,
}
}

/// The fee that is charged to a user for executing an order.
#[derive(Clone, Copy, Debug)]
pub enum Fee {
Expand Down
36 changes: 35 additions & 1 deletion src/domain/solver/dex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use {
},
infra,
},
ethereum_types::U256,
futures::{future, stream, FutureExt, StreamExt},
std::num::NonZeroUsize,
tracing::Instrument,
Expand Down Expand Up @@ -188,7 +189,7 @@ impl Dex {
let dex_order = self.fills.dex_order(order, tokens)?;
let swap = self.try_solve(order, &dex_order, tokens).await?;
let sell = tokens.reference_price(&order.sell.token);
let Some(solution) = swap
let Some(mut solution) = swap
.into_solution(
order.clone(),
gas_price,
Expand All @@ -202,6 +203,39 @@ impl Dex {
return None;
};

// Filter out the trades which do not respect the limit price
solution.trades = solution
.trades
.into_iter()
.filter_map(|trade| {
let buy_price = U256::from(
tokens
.get(&trade.buy_token())
.and_then(|token| token.reference_price)?,
);
let sell_price = U256::from(
tokens
.get(&trade.sell_token())
.and_then(|token| token.reference_price)?,
);

let buy_amount = trade.buy_amount(buy_price, sell_price).ok()?;
let sell_amount = trade.sell_amount(buy_price, sell_price).ok()?;

if sell_amount.checked_mul(sell_price)? >= buy_amount.checked_mul(buy_price)? {
Some(trade)
} else {
tracing::warn!(
?trade,
?tokens,
"Settlement contract rule not fulfilled: order.sellAmount.mul(sellPrice) \
>= order.buyAmount.mul(buyPrice)"
);
None
}
})
.collect();

tracing::debug!("solved");
// Maybe some liquidity appeared that enables a bigger fill.
self.fills.increase_next_try(order.uid);
Expand Down
Loading