-
Notifications
You must be signed in to change notification settings - Fork 97
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
Price improvement tests #2467
Changes from all commits
9b3a0ee
dd233e2
3f7bf5e
4b70eb7
38135e8
287c1f9
08c7027
758ebde
3a80fe6
75d99c1
47dd239
1a47343
9daf971
886fc2f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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); | ||
|
@@ -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); | ||
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() { | ||
|
@@ -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] | ||
|
@@ -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] | ||
|
@@ -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] | ||
|
@@ -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()), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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)
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} |
There was a problem hiding this comment.
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?