Skip to content

Commit

Permalink
Check if limit price is respected
Browse files Browse the repository at this point in the history
  • Loading branch information
m-lord-renkse committed Nov 22, 2024
1 parent ee8bba6 commit 8fdd0af
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 2 deletions.
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

0 comments on commit 8fdd0af

Please sign in to comment.