Skip to content

Commit

Permalink
Test: JIT orders surplus support for cow amm (#2699)
Browse files Browse the repository at this point in the history
# Description
Tests for the JIT orders surplus support PR:
#2682
  • Loading branch information
m-lord-renkse authored Jul 24, 2024
1 parent 0ed1c76 commit 681faa0
Show file tree
Hide file tree
Showing 8 changed files with 666 additions and 183 deletions.
2 changes: 2 additions & 0 deletions crates/driver/src/tests/boundary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct Order {
pub sell_amount: ethcontract::U256,
pub buy_amount: ethcontract::U256,
pub valid_to: u32,
pub receiver: Option<ethcontract::H160>,
pub user_fee: ethcontract::U256,
pub side: competition::order::Side,
pub secret_key: SecretKey,
Expand All @@ -36,6 +37,7 @@ impl Order {
.with_buy_amount(self.buy_amount)
.with_valid_to(self.valid_to)
.with_fee_amount(self.user_fee)
.with_receiver(self.receiver)
.with_kind(match self.side {
competition::order::Side::Buy => model::order::OrderKind::Buy,
competition::order::Side::Sell => model::order::OrderKind::Sell,
Expand Down
183 changes: 183 additions & 0 deletions crates/driver/src/tests/cases/jit_orders.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
use crate::{
domain::{
competition::{order, order::Side},
eth,
},
tests::{
self,
cases::{is_approximately_equal, EtherExt},
setup::{
self,
ab_adjusted_pool,
ab_liquidity_quote,
ab_order,
ab_solution,
test_solver,
Test,
},
},
};

struct Amounts {
sell: eth::U256,
buy: eth::U256,
}

struct Execution {
// The executed net-amounts (including network fee) reported by the solver
solver: Amounts,
// The executed net-amounts (including network and protocol) reported by the driver
driver: Amounts,
}

struct Order {
sell_amount: eth::U256,
buy_amount: eth::U256,
side: order::Side,
}

struct JitOrder {
order: Order,
}

struct Solution {
jit_order: JitOrder,
expected_score: eth::U256,
}

struct TestCase {
order: Order,
execution: Execution,
is_surplus_capturing_jit_order: bool,
solution: Solution,
}

#[cfg(test)]
async fn protocol_fee_test_case(test_case: TestCase) {
let test_name = format!("JIT Order: {:?}", test_case.order.side);
// Adjust liquidity pools so that the order is executable at the amounts
// expected from the solver.
let quote = ab_liquidity_quote()
.sell_amount(test_case.execution.solver.sell)
.buy_amount(test_case.execution.solver.buy);
let pool = ab_adjusted_pool(quote);
let solver_fee = test_case.execution.driver.sell / 100;

let jit_order = setup::JitOrder {
order: ab_order()
.kind(order::Kind::Limit)
.sell_amount(test_case.solution.jit_order.order.sell_amount)
.buy_amount(test_case.solution.jit_order.order.buy_amount)
.solver_fee(Some(solver_fee))
.side(test_case.solution.jit_order.order.side)
.no_surplus(),
};

let order = ab_order()
.kind(order::Kind::Limit)
.sell_amount(test_case.order.sell_amount)
.buy_amount(test_case.order.buy_amount)
.solver_fee(Some(solver_fee))
.side(test_case.order.side)
.partial(0.into())
.no_surplus();

let solver = test_solver();
let test: Test = tests::setup()
.name(test_name)
.pool(pool)
.jit_order(jit_order.clone())
.order(order.clone())
.solution(ab_solution())
.surplus_capturing_jit_order_owners(
test_case
.is_surplus_capturing_jit_order
.then(|| vec![solver.address()])
.unwrap_or_default(),
)
.solvers(vec![solver])
.done()
.await;

let result = test.solve().await.ok();
assert!(is_approximately_equal(
result.score(),
test_case.solution.expected_score,
));
}

#[tokio::test]
#[ignore]
async fn surplus_protocol_fee_jit_order_from_surplus_capturing_owner_not_capped() {
let test_case = TestCase {
order: Order {
sell_amount: 50.ether().into_wei(),
buy_amount: 40.ether().into_wei(),
side: Side::Buy,
},
execution: Execution {
// 20 ETH surplus in sell token (after network fee), half of which is kept by the
// protocol
solver: Amounts {
sell: 30.ether().into_wei(),
buy: 40.ether().into_wei(),
},
driver: Amounts {
sell: 40.ether().into_wei(),
buy: 40.ether().into_wei(),
},
},
is_surplus_capturing_jit_order: true,
solution: Solution {
jit_order: JitOrder {
order: Order {
sell_amount: 50.ether().into_wei(),
buy_amount: 40.ether().into_wei(),
side: Side::Buy,
},
},
// Score is 20 x 2 since there are two orders with score 20 (user order + JIT order)
expected_score: 40.ether().into_wei(),
},
};

protocol_fee_test_case(test_case).await;
}

#[tokio::test]
#[ignore]
async fn surplus_protocol_fee_jit_order_not_capped() {
let test_case = TestCase {
order: Order {
sell_amount: 50.ether().into_wei(),
buy_amount: 40.ether().into_wei(),
side: Side::Buy,
},
execution: Execution {
// 20 ETH surplus in sell token (after network fee), half of which is kept by the
// protocol
solver: Amounts {
sell: 30.ether().into_wei(),
buy: 40.ether().into_wei(),
},
driver: Amounts {
sell: 40.ether().into_wei(),
buy: 40.ether().into_wei(),
},
},
is_surplus_capturing_jit_order: false,
solution: Solution {
jit_order: JitOrder {
order: Order {
sell_amount: 50.ether().into_wei(),
buy_amount: 40.ether().into_wei(),
side: Side::Buy,
},
},
// Score is 20 since the JIT order is not from a surplus capturing owner
expected_score: 20.ether().into_wei(),
},
};

protocol_fee_test_case(test_case).await;
}
12 changes: 12 additions & 0 deletions crates/driver/src/tests/cases/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod buy_eth;
pub mod example_config;
pub mod fees;
pub mod internalization;
pub mod jit_orders;
pub mod merge_settlements;
pub mod multiple_drivers;
pub mod multiple_solutions;
Expand Down Expand Up @@ -116,3 +117,14 @@ impl EtherExt for f64 {
Ether(BigRational::from_f64(self).unwrap())
}
}

// because of rounding errors, it's good enough to check that the expected value
// is within a very narrow range of the executed value
#[cfg(test)]
pub fn is_approximately_equal(executed_value: eth::U256, expected_value: eth::U256) -> bool {
let lower =
expected_value * eth::U256::from(99999999999u128) / eth::U256::from(100000000000u128); // in percents = 99.999999999%
let upper =
expected_value * eth::U256::from(100000000001u128) / eth::U256::from(100000000000u128); // in percents = 100.000000001%
executed_value >= lower && executed_value <= upper
}
14 changes: 2 additions & 12 deletions crates/driver/src/tests/cases/protocol_fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
infra::config::file::FeeHandler,
tests::{
self,
cases::EtherExt,
cases::{is_approximately_equal, EtherExt},
setup::{
ab_adjusted_pool,
ab_liquidity_quote,
Expand Down Expand Up @@ -43,17 +43,6 @@ struct TestCase {
fee_handler: FeeHandler,
}

// because of rounding errors, it's good enough to check that the expected value
// is within a very narrow range of the executed value
#[cfg(test)]
fn is_approximately_equal(executed_value: eth::U256, expected_value: eth::U256) -> bool {
let lower =
expected_value * eth::U256::from(99999999999u128) / eth::U256::from(100000000000u128); // in percents = 99.999999999%
let upper =
expected_value * eth::U256::from(100000000001u128) / eth::U256::from(100000000000u128); // in percents = 100.000000001%
executed_value >= lower && executed_value <= upper
}

#[cfg(test)]
async fn protocol_fee_test_case(test_case: TestCase) {
let test_name = format!(
Expand All @@ -78,6 +67,7 @@ async fn protocol_fee_test_case(test_case: TestCase) {
sell: test_case.execution.driver.sell,
buy: test_case.execution.driver.buy,
};

let order = ab_order()
.kind(order::Kind::Limit)
.sell_amount(test_case.order.sell_amount)
Expand Down
Loading

0 comments on commit 681faa0

Please sign in to comment.