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

Price improvement tests #2467

Closed
wants to merge 14 commits into from
242 changes: 208 additions & 34 deletions crates/driver/src/tests/cases/protocol_fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,40 @@ use crate::{
ab_solution,
ExpectedOrderAmounts,
FeePolicy,
PriceImprovementQuote,
Test,
},
},
};

struct TestCase {
const DEFAULT_SURPLUS_FACTOR: u64 = 2;

struct CommonTestCase {
order_side: order::Side,
fee_policy: FeePolicy,
order_sell_amount: eth::U256,
solver_fee: Option<eth::U256>,
network_fee: Option<eth::U256>,
quote_sell_amount: eth::U256,
quote_buy_amount: eth::U256,
executed: eth::U256,
executed_sell_amount: eth::U256,
executed_buy_amount: eth::U256,
}

async fn protocol_fee_test_case(test_case: TestCase) {
struct PriceImprovementTestCase {
order_side: order::Side,
policy_factor: f64,
policy_max_volume_factor: f64,
quote: PriceImprovementQuote,
order_sell_amount: eth::U256,
order_buy_amount: eth::U256,
network_fee: Option<eth::U256>,
executed: eth::U256,
executed_sell_amount: eth::U256,
executed_buy_amount: eth::U256,
}

async fn common_fee_test_case(test_case: CommonTestCase) {
let test_name = format!(
"Protocol Fee: {:?} {:?}",
test_case.order_side, test_case.fee_policy
Expand All @@ -41,10 +57,11 @@ async fn protocol_fee_test_case(test_case: TestCase) {
buy: test_case.executed_buy_amount,
};
let order = ab_order()
.surplus(DEFAULT_SURPLUS_FACTOR.into())
.kind(order::Kind::Limit)
.sell_amount(test_case.order_sell_amount)
.side(test_case.order_side)
.solver_fee(test_case.solver_fee)
.solver_fee(test_case.network_fee)
.fee_policy(test_case.fee_policy)
.executed(test_case.executed)
.expected_amounts(expected_amounts);
Expand All @@ -59,6 +76,41 @@ async fn protocol_fee_test_case(test_case: TestCase) {
test.solve().await.ok().orders(&[order]);
}

async fn price_improvement_fee_test_case(test_case: PriceImprovementTestCase) {
let test_name = format!("Protocol Fee: {:?} PriceImprovement", test_case.order_side);
let liquidity_quote = ab_liquidity_quote()
.sell_amount(test_case.order_sell_amount)
.buy_amount(test_case.order_buy_amount);
Comment on lines +82 to +83
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that set from the order amounts and not from the quote?

let pool = ab_adjusted_pool(liquidity_quote);
let expected_amounts = ExpectedOrderAmounts {
sell: test_case.executed_sell_amount,
buy: test_case.executed_buy_amount,
};
let fee_policy = FeePolicy::PriceImprovement {
factor: test_case.policy_factor,
max_volume_factor: test_case.policy_max_volume_factor,
quote: test_case.quote,
};
let order = ab_order()
.no_surplus()
.kind(order::Kind::Limit)
.sell_amount(test_case.order_sell_amount)
.side(test_case.order_side)
.solver_fee(test_case.network_fee)
.fee_policy(fee_policy)
.executed(test_case.executed)
.expected_amounts(expected_amounts);
let test: Test = tests::setup()
.name(test_name)
.pool(pool)
.order(order.clone())
.solution(ab_solution())
.done()
.await;

test.solve().await.ok().orders(&[order]);
}

#[tokio::test]
#[ignore]
async fn surplus_protocol_fee_buy_order_not_capped() {
Expand All @@ -67,19 +119,21 @@ async fn surplus_protocol_fee_buy_order_not_capped() {
// high enough so we don't get capped by volume fee
max_volume_factor: 1.0,
};
let test_case = TestCase {
let order_buy_amount = 40.ether().into_wei();
let order_sell_amount = 50.ether().into_wei();
let test_case = CommonTestCase {
order_side: order::Side::Buy,
fee_policy,
order_sell_amount: 50.ether().into_wei(),
solver_fee: Some(10.ether().into_wei()),
quote_sell_amount: 50.ether().into_wei(),
quote_buy_amount: 40.ether().into_wei(),
executed: 40.ether().into_wei(),
executed_sell_amount: 100.ether().into_wei(),
executed_buy_amount: 40.ether().into_wei(),
order_sell_amount,
network_fee: Some(10.ether().into_wei()),
quote_sell_amount: order_sell_amount,
quote_buy_amount: order_buy_amount,
executed: order_buy_amount,
executed_sell_amount: 75.ether().into_wei(),
executed_buy_amount: order_buy_amount,
};

protocol_fee_test_case(test_case).await;
common_fee_test_case(test_case).await;
}

#[tokio::test]
Expand All @@ -90,19 +144,21 @@ async fn surplus_protocol_fee_sell_order_not_capped() {
// high enough so we don't get capped by volume fee
max_volume_factor: 1.0,
};
let test_case = TestCase {
let order_sell_amount = 50.ether().into_wei();
let order_buy_amount = 40.ether().into_wei();
let test_case = CommonTestCase {
order_side: order::Side::Sell,
fee_policy,
order_sell_amount: 50.ether().into_wei(),
solver_fee: Some(10.ether().into_wei()),
quote_sell_amount: 50.ether().into_wei(),
quote_buy_amount: 40.ether().into_wei(),
executed: 40.ether().into_wei(),
executed_sell_amount: 50.ether().into_wei(),
executed_buy_amount: "20.000000002".ether().into_wei(),
order_sell_amount,
network_fee: Some(10.ether().into_wei()),
quote_sell_amount: order_sell_amount,
quote_buy_amount: order_buy_amount,
executed: order_buy_amount,
executed_sell_amount: order_sell_amount,
executed_buy_amount: 30.ether().into_wei(),
};

protocol_fee_test_case(test_case).await;
common_fee_test_case(test_case).await;
}

#[tokio::test]
Expand All @@ -113,19 +169,19 @@ async fn surplus_protocol_fee_buy_order_capped() {
// low enough so we get capped by volume fee
max_volume_factor: 0.1,
};
let test_case = TestCase {
let test_case = CommonTestCase {
order_side: order::Side::Buy,
fee_policy,
order_sell_amount: 50.ether().into_wei(),
solver_fee: Some(10.ether().into_wei()),
network_fee: Some(10.ether().into_wei()),
quote_sell_amount: 50.ether().into_wei(),
quote_buy_amount: 40.ether().into_wei(),
executed: 40.ether().into_wei(),
executed_sell_amount: 55.ether().into_wei(),
executed_buy_amount: 40.ether().into_wei(),
};

protocol_fee_test_case(test_case).await;
common_fee_test_case(test_case).await;
}

#[tokio::test]
Expand All @@ -136,55 +192,173 @@ async fn surplus_protocol_fee_sell_order_capped() {
// low enough so we get capped by volume fee
max_volume_factor: 0.1,
};
let test_case = TestCase {
let test_case = CommonTestCase {
order_side: order::Side::Sell,
fee_policy,
order_sell_amount: 50.ether().into_wei(),
solver_fee: Some(10.ether().into_wei()),
network_fee: Some(10.ether().into_wei()),
quote_sell_amount: 50.ether().into_wei(),
quote_buy_amount: 40.ether().into_wei(),
executed: 40.ether().into_wei(),
executed_sell_amount: 50.ether().into_wei(),
executed_buy_amount: 36.ether().into_wei(),
};

protocol_fee_test_case(test_case).await;
common_fee_test_case(test_case).await;
}

#[tokio::test]
#[ignore]
async fn volume_protocol_fee_buy_order() {
let fee_policy = FeePolicy::Volume { factor: 0.5 };
let test_case = TestCase {
let test_case = CommonTestCase {
order_side: order::Side::Buy,
fee_policy,
order_sell_amount: 50.ether().into_wei(),
solver_fee: Some(10.ether().into_wei()),
network_fee: Some(10.ether().into_wei()),
quote_sell_amount: 50.ether().into_wei(),
quote_buy_amount: 40.ether().into_wei(),
executed: 40.ether().into_wei(),
executed_sell_amount: 75.ether().into_wei(),
executed_buy_amount: 40.ether().into_wei(),
};

protocol_fee_test_case(test_case).await;
common_fee_test_case(test_case).await;
}

#[tokio::test]
#[ignore]
async fn volume_protocol_fee_sell_order() {
let fee_policy = FeePolicy::Volume { factor: 0.5 };
let test_case = TestCase {
let test_case = CommonTestCase {
order_side: order::Side::Sell,
fee_policy,
order_sell_amount: 50.ether().into_wei(),
solver_fee: Some(10.ether().into_wei()),
network_fee: Some(10.ether().into_wei()),
quote_sell_amount: 50.ether().into_wei(),
quote_buy_amount: 40.ether().into_wei(),
executed: 40.ether().into_wei(),
executed_sell_amount: 50.ether().into_wei(),
executed_buy_amount: 20.ether().into_wei(),
};

protocol_fee_test_case(test_case).await;
common_fee_test_case(test_case).await;
}

// Price Improvement policy fee tests.
// Out of market order could be defined as:
// (order.sell + order.fee) * quote.buy < (quote.sell + quote.fee) * order.buy
// In the following tests Limit orders are used only, where order fee is 0. The
// amount values are adjusted to respect the definition.

#[tokio::test]
#[ignore]
async fn price_improvement_fee_buy_out_of_market_order() {
let order_sell_amount = 50.ether().into_wei();
let order_buy_amount = 40.ether().into_wei();
let quote_network_fee = 20.ether().into_wei();
let quote = PriceImprovementQuote {
sell_amount: order_sell_amount,
buy_amount: order_buy_amount,
network_fee: quote_network_fee,
};
let test_case = PriceImprovementTestCase {
order_side: order::Side::Buy,
policy_factor: 0.5,
policy_max_volume_factor: 1.0,
quote,
order_sell_amount,
order_buy_amount,
network_fee: Some(1.ether().into_wei()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are still not saying anywhere that this is the little detail that leads to price improvement. This is way to hidden to leave this uncommented.

executed: order_buy_amount,
// order sell amount + quote network fee * factor
executed_sell_amount: 60.ether().into_wei(),
executed_buy_amount: order_buy_amount,
};

price_improvement_fee_test_case(test_case).await;
}

#[tokio::test]
#[ignore]
async fn price_improvement_fee_sell_out_of_market_order() {
let order_sell_amount = 50.ether().into_wei();
let order_buy_amount = 40.ether().into_wei();
let quote = PriceImprovementQuote {
sell_amount: order_sell_amount,
buy_amount: order_buy_amount,
network_fee: 20.ether().into_wei(),
};
let network_fee = 10.ether().into_wei();
let test_case = PriceImprovementTestCase {
order_side: order::Side::Sell,
policy_factor: 0.5,
policy_max_volume_factor: 1.0,
quote,
order_sell_amount,
order_buy_amount,
network_fee: Some(network_fee),
executed: order_sell_amount - network_fee,
executed_sell_amount: order_sell_amount,
// todo: how to prove the value?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well how is it calculated? Comment with the math that leads to this value.

Let's maybe start by "where is the price improvement coming from in this test"? I see sell amount and buy amounts and network fees are equal for quote and orders. Unclear why there is any price improvement fee here?

executed_buy_amount: "34.285714285714285714".ether().into_wei(),
};

price_improvement_fee_test_case(test_case).await;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially fillable orders are missing.

Also can we add a test that shows shifting surplus into network fees doesn't change the protocol fee charged? E.g. the following two executions pay the same fee (assuming same underlying orders & quotes)

  1. Sell 0.1 ETH receive 3500 DAI, pay 0.9 ETH in network fees
  2. Sell 1 ETH receive 3500 DAI, pay 0 in network fees

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially fillable orders require some further refactoring. I will create a separate issue for this.


#[tokio::test]
#[ignore]
async fn price_improvement_fee_buy_in_market_order() {
let order_sell_amount = 100.ether().into_wei();
let order_buy_amount = 40.ether().into_wei();
let quote = PriceImprovementQuote {
sell_amount: 50.ether().into_wei(),
buy_amount: 40.ether().into_wei(),
network_fee: 20.ether().into_wei(),
};
let network_fee = 10.ether().into_wei();
let test_case = PriceImprovementTestCase {
order_side: order::Side::Buy,
policy_factor: 0.5,
policy_max_volume_factor: 1.0,
quote,
order_sell_amount,
order_buy_amount,
network_fee: Some(network_fee),
executed: order_buy_amount,
// no price improvement since quote provides better conditions
executed_sell_amount: order_sell_amount,
executed_buy_amount: order_buy_amount,
};

price_improvement_fee_test_case(test_case).await;
}

#[tokio::test]
#[ignore]
async fn price_improvement_fee_sell_in_market_order() {
let order_sell_amount: eth::U256 = 50.ether().into_wei();
let order_buy_amount: eth::U256 = 10.ether().into_wei();
let quote = PriceImprovementQuote {
sell_amount: 50.ether().into_wei(),
buy_amount: 40.ether().into_wei(),
network_fee: 20.ether().into_wei(),
};
let network_fee = 10.ether().into_wei();
let test_case = PriceImprovementTestCase {
order_side: order::Side::Sell,
policy_factor: 0.5,
policy_max_volume_factor: 1.0,
quote,
order_sell_amount,
order_buy_amount,
network_fee: Some(network_fee),
executed: order_sell_amount - network_fee,
// no price improvement since quote provides better conditions
executed_sell_amount: order_sell_amount,
executed_buy_amount: order_buy_amount,
};

price_improvement_fee_test_case(test_case).await;
}
Loading
Loading