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

Partially fillable orders in driver tests #2512

Merged
merged 20 commits into from
Mar 18, 2024

Conversation

squadgazzz
Copy link
Contributor

@squadgazzz squadgazzz commented Mar 12, 2024

Description

Adds support for partially fillable orders in the driver's integration tests

Related Issues

Fixes #2480

@squadgazzz squadgazzz force-pushed the 2480/partially-fillable-driver-tests branch from 0bcd6e3 to 36617c8 Compare March 13, 2024 15:34
@squadgazzz squadgazzz force-pushed the 2480/partially-fillable-driver-tests branch from 36617c8 to 9c9bf73 Compare March 13, 2024 15:53
@squadgazzz squadgazzz force-pushed the 2480/partially-fillable-driver-tests branch from e196e42 to 2f844ef Compare March 13, 2024 17:23
@squadgazzz squadgazzz changed the title Draft: Partially fillable orders in driver tests Partially fillable orders in driver tests Mar 13, 2024
@squadgazzz squadgazzz marked this pull request as ready for review March 13, 2024 20:24
@squadgazzz squadgazzz requested a review from a team as a code owner March 13, 2024 20:24
@squadgazzz squadgazzz force-pushed the 2480/partially-fillable-driver-tests branch from c16bd88 to 8ebca7a Compare March 13, 2024 20:52
Copy link
Contributor

@fleupold fleupold left a comment

Choose a reason for hiding this comment

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

Haven't checked the test cases in depth yet. I'm still a bit confused by the changes to the core tests (I'm pretty sure partial is mis-appropriated from reading the comments in the code)

Comment on lines +131 to +133
/// Override the executed target amount of the order. Useful for testing
/// liquidity orders. Otherwise [`execution_diff`] is probably more
/// suitable.
Copy link
Contributor

Choose a reason for hiding this comment

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

We are not testing liquidity order though, are we? I wonder if executed is even needed or if we can instead use ab_adjusted_pool(quote) to control how much is executed. Have you checked that?

Copy link
Contributor Author

@squadgazzz squadgazzz Mar 14, 2024

Choose a reason for hiding this comment

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

You mean to pass order's full amount into this function?

pub fn out_given_in(&self, input: Asset) -> eth::U256 {

That doesn't work since ab_adjusted_pool function adjusts one of the pool's reserves to align with the quote's ratio. For different inputs, the pool returns different results.

@@ -570,6 +608,20 @@ impl Blockchain {
}),
buy_amount,
),
// todo: simplify it
Copy link
Contributor

Choose a reason for hiding this comment

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

Please do. This conditional is now very hard to read. I think we should have two conditional, one checks if there is an explicit amount set (in which case we use it, using in_given_out for buys and out_given_in for sells, otherwise we use the whole sell amount out_given_in. Ideally we would even get rid of this optionality as I feel it's quite hard to understand already.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Applied your suggestion, thanks!

let executed = match partial {
Partial::Yes { .. } => match test_case.order.side {
order::Side::Buy => Some(test_case.execution.solver.buy),
order::Side::Sell => Some(test_case.execution.solver.sell - solver_fee),
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we subtract the solver fee here? Shouldn't the whole partial sell amount be executed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since executed amount is filled manually, the logic replicates this code.

Partial::No
} else {
Partial::Yes {
executed: partially_executed,
Copy link
Contributor

Choose a reason for hiding this comment

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

/// The available amount that can be used from the order.
///
/// This amount considers both how much of the order has already been
/// executed as well as the trader's balance.
available: TargetAmount,

This value is meant to say how much of the order has already been filled in previous settlement. This is indeed another test scenario (having an order be filled partially multiple times and check that each fee is correct), but I don't believe you are trying to test this here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to zero amount

@@ -131,6 +131,44 @@ impl QuotedOrder {
}
}

/// Calculates buy amount that should be received from a driver
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this mean? Why is this necessary and different to e.g. executed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed

side: order::Side::Buy,
},
execution: Execution {
// 6 ETH surplus in sell token (after network fee), half of which is kept by the
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we simplify this example by using more round fractions (e.g. have the order be ratiod 1:1 or 1:2 and partially match it 50%)?

This way it's easy to see the surplus (here you need to do some non-trivial math)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Simplified the amounts.

Copy link
Contributor

@fleupold fleupold left a comment

Choose a reason for hiding this comment

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

See https://github.com/cowprotocol/services/compare/2512 for a concrete suggestion and a single test case.

@squadgazzz
Copy link
Contributor Author

squadgazzz commented Mar 14, 2024

See https://github.com/cowprotocol/services/compare/2512 for a concrete suggestion and a single test case.

Applied the suggestion but with the following changes:

.map(|amount| amount + order.solver_fee.unwrap_or_default())

Some(test_case.execution.solver.sell - solver_fee)

Without this, sell orders don't work properly.

@squadgazzz squadgazzz force-pushed the 2480/partially-fillable-driver-tests branch from 723515a to 9548109 Compare March 14, 2024 19:23
@squadgazzz squadgazzz force-pushed the 2480/partially-fillable-driver-tests branch from faba3dc to 38469a3 Compare March 14, 2024 19:33
Copy link
Contributor

@fleupold fleupold left a comment

Choose a reason for hiding this comment

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

LGTM

squadgazzz and others added 2 commits March 15, 2024 15:01
Co-authored-by: Felix Leupold <felixleupold90@gmail.com>
Copy link
Contributor

@MartinquaXD MartinquaXD left a comment

Choose a reason for hiding this comment

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

Looks alright to me. Just slightly surprised about the case where we apply a price improvement fee on an out-of-market order. Overall the chosen values help to follow the math in your head. 👍

order::Side::Buy => (test_case.order.buy_amount > test_case.execution.solver.buy)
.then_some(test_case.execution.solver.buy),
order::Side::Sell => {
if test_case.order.sell_amount > test_case.execution.solver.sell {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: why use .then_some() in one case and if else in another?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Forgot to update it, thanks

let test_case = TestCase {
fee_policy,
order: Order {
// Demanding to sell less than quoted (out-market)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we expect a price improvement fee to ever apply to an out-of-market order?
In this case we are falling back to taking a fee compared to the limit price, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

In this case price improvement behaves exactly like Surplus fees (assuming the same factor). Depending on the final fee policy that is decided we may be able to use a single fee policy for all order types.

@squadgazzz squadgazzz enabled auto-merge (squash) March 18, 2024 13:15
@squadgazzz squadgazzz merged commit 413bc1a into main Mar 18, 2024
9 checks passed
@squadgazzz squadgazzz deleted the 2480/partially-fillable-driver-tests branch March 18, 2024 13:19
@github-actions github-actions bot locked and limited conversation to collaborators Mar 18, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support partially fillable orders in driver integration tests
4 participants