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

Simulate Trades in Solver #1960

Merged
merged 14 commits into from
Oct 18, 2023
Merged

Simulate Trades in Solver #1960

merged 14 commits into from
Oct 18, 2023

Conversation

nlordell
Copy link
Contributor

@nlordell nlordell commented Oct 13, 2023

Description

Supersedes #1531

#1469 introduced simulations to the single order solvers so that we can produce accurate fees when solving for partially fillable limit orders. This PR ports some of that logic to our solvers binary for the DEX aggregator solvers in the co-located world.

In particular, it introduces a new Swapper helper contract for setting up simulations on-chain for DEX aggregator swaps. We also only do the simulation for limit orders (to avoid additional roudtrips for market orders, which don't use this gas information anyway, so the heuristic value is more than good enough).

Changes

  • Introduce new simulation helper contract.
  • Execute simulations for limit orders and use the simulated gas amount for computing accurate solver fees.
  • TODO: Mock node request/responses for executing the simulation in the partial_fill tests.

How to test

Adjusted some existing tests to work.

Related Issues

Fixes #1959

@nlordell nlordell requested a review from a team as a code owner October 13, 2023 10:24
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.

Neat!
Will push it over the finish line for you.

@@ -94,7 +94,30 @@ async fn tested_amounts_adjust_depending_on_response() {
])
.await;

let engine = tests::SolverEngine::new("balancer", balancer::config(&api.address)).await;
let simulation_node = mock::http::setup(vec![mock::http::Expectation::Post {
path: mock::http::Path::Any,
Copy link
Contributor

Choose a reason for hiding this comment

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

I decided to not test the request value because it's pretty huge and not really readable so I think there is no way to check whether that value is correct by reading the test.
If something inside the simulation logic were to change the only way to make the test pass again would be to print the generated request and paste it as the expectation which defeats the purpose of having a hard coded expectation.
LMK in case you disagree.

example request

2023-10-13T13:20:57.122Z ERROR solvers::tests::mock::http: value req=Object {"id": Number(0), "jsonrpc": String("2.0"), "method": String("eth_call"), "params": Array [Object {"data": String("0x9ed280dd0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d00000000000000000000000000000000000000000000000c569150947c02824e000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c80000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002e4945bcec90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002200000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab4100000000000000000000000000000000000000000000000000000000000000000000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002808000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000205c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000de0b6b3a7640000fffffffffffffffffffffffffffffffffffffffffffffff3c9049e4e47ca50ec00000000000000000000000000000000000000000000000000000000"), "to": String("0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a")}, String("latest"), Object {"0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a": Object {"code": String("0x608060405234801561001057600080fd5b50600436106100365760003560e01c80631626ba7e1461003b5780639ed280dd146100a7575b600080fd5b610071610049366004610b03565b7f1626ba7e000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b6100ba6100b5366004610bbc565b6100c8565b60405190815260200161009e565b6000602085018035906100db9087610c49565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91909116906370a0823190602401602060405180830381865afa158015610147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061016b9190610c66565b1015610179575060006108b8565b6102178673ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101eb9190610c7f565b60006101fa6020890189610c49565b73ffffffffffffffffffffffffffffffffffffffff1691906108c1565b61029a8673ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610265573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102899190610c7f565b602087018035906101fa9089610c49565b6040805160028082526060820183526000926020830190803683370190505090506102c86020870187610c49565b816000815181106102db576102db610ccb565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015261030b90860186610c49565b8160018151811061031e5761031e610ccb565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101820152604080516002808252606082018352600093919290918301908036833701905050905085602001358160008151811061037e5761037e610ccb565b6020026020010181815250508660200135816001815181106103a2576103a2610ccb565b6020908102919091010152604080516001808252818301909252600091816020015b6104406040518061016001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600063ffffffff16815260200160008019168152602001600081526020016000815260200160008152602001606081525090565b8152602001906001900390816103c45790505090506040518061016001604052806000815260200160018152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001896020013581526020018860200135815260200163ffffffff801681526020016000801b815260200160008152602001604081526020016000815260200130604051602001610506919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b6040516020818303038152906040528152508160008151811061052b5761052b610ccb565b602002602001018190525061053e610adc565b60208088013590610551908b018b610c49565b73ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8c61057a60208c018c610c49565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa1580156105ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060e9190610c66565b101561078c5760408051600180825281830190925290816020015b60408051606080820183526000808352602083015291810191909152815260200190600190039081610629575050815261066660208a018a610c49565b8151805160009061067957610679610ccb565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff9092169091526106ac908a018a610c49565b73ffffffffffffffffffffffffffffffffffffffff1663095ea7b36106d460208a018a610c49565b60405173ffffffffffffffffffffffffffffffffffffffff909116602482015260208a01356044820152606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b929092179091529050816000602002015160008151811061077c5761077c610ccb565b6020026020010151604001819052505b60408051600180825281830190925290816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816107a157505060208201526107dd86610d72565b602082015180516000906107f3576107f3610ccb565b60200260200101819052506108b18a73ffffffffffffffffffffffffffffffffffffffff166313d79a0b868686866040516024016108349493929190611071565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09390931b9290921790915273ffffffffffffffffffffffffffffffffffffffff8d16915061099c565b9450505050505b95945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905290600090610954908616836109b1565b9050610995816040518060400160405280601a81526020017f5361666545524332303a20617070726f76616c206661696c65640000000000008152506109bf565b5050505050565b60006109aa83600084610a23565b9392505050565b60606109aa83600084610a56565b815115806109dc5750818060200190518101906109dc919061112a565b8190610a1e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a15919061114c565b60405180910390fd5b505050565b60005a905060008083516020850186885af1610a43573d6000803e3d6000fd5b5a610a4e908261115f565b949350505050565b606060008473ffffffffffffffffffffffffffffffffffffffff168484604051610a80919061119f565b60006040518083038185875af1925050503d8060008114610abd576040519150601f19603f3d011682016040523d82523d6000602084013e610ac2565b606091505b509250905080610ad457815160208301fd5b509392505050565b60405180606001604052806003905b6060815260200190600190039081610aeb5790505090565b600080600060408486031215610b1857600080fd5b83359250602084013567ffffffffffffffff80821115610b3757600080fd5b818601915086601f830112610b4b57600080fd5b813581811115610b5a57600080fd5b876020828501011115610b6c57600080fd5b6020830194508093505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff81168114610ba157600080fd5b50565b600060408284031215610bb657600080fd5b50919050565b60008060008060006101008688031215610bd557600080fd5b8535610be081610b7f565b9450610bef8760208801610ba4565b9350610bfe8760608801610ba4565b9250610c0d8760a08801610ba4565b915060e086013567ffffffffffffffff811115610c2957600080fd5b860160608189031215610c3b57600080fd5b809150509295509295909350565b600060208284031215610c5b57600080fd5b81356109aa81610b7f565b600060208284031215610c7857600080fd5b5051919050565b600060208284031215610c9157600080fd5b81516109aa81610b7f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6040516060810167ffffffffffffffff81118282101715610d1d57610d1d610c9c565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d6a57610d6a610c9c565b604052919050565b600060608236031215610d8457600080fd5b610d8c610cfa565b8235610d9781610b7f565b815260208381013581830152604084013567ffffffffffffffff80821115610dbe57600080fd5b9085019036601f830112610dd157600080fd5b813581811115610de357610de3610c9c565b610e13847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610d23565b91508082523684828501011115610e2957600080fd5b808484018584013760009082019093019290925250604082015292915050565b60005b83811015610e64578181015183820152602001610e4c565b50506000910152565b60008151808452610e85816020860160208601610e49565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015610f975782840389528151610160815186528682015187870152604080830151610f1a8289018273ffffffffffffffffffffffffffffffffffffffff169052565b5050606082810151908701526080808301519087015260a08083015163ffffffff169087015260c0808301519087015260e080830151908701526101008083015190870152610120808301519087015261014091820151918601819052610f8381870183610e6d565b9a87019a9550505090840190600101610ed5565b5091979650505050505050565b6000826060808201846000805b6003811015610f97578584038952825180518086526020918201918087019190600582901b88018101865b8381101561105a578982037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00185528551805173ffffffffffffffffffffffffffffffffffffffff16835283810151848401526040908101519083018c90526110478c840182610e6d565b9684019695840195925050600101610fdc565b509c81019c97509590950194505050600101610fb1565b6080808252855190820181905260009060209060a0840190828901845b828110156110c057815173ffffffffffffffffffffffffffffffffffffffff168452928401929084019060010161108e565b5050508381038285015286518082528783019183019060005b818110156110f5578351835292840192918401916001016110d9565b505084810360408601526111098188610eb7565b92505050828103606084015261111f8185610fa4565b979650505050505050565b60006020828403121561113c57600080fd5b815180151581146109aa57600080fd5b6020815260006109aa6020830184610e6d565b81810381811115611199577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b92915050565b600082516111b1818460208701610e49565b919091019291505056fea164736f6c6343000811000a")}, "0x2c4c28ddbdac9c5e7055b4c863b72ea0149d8afe": Object {"code": String("0x6080604052348015600f57600080fd5b506004361060285760003560e01c806302cc250d14602d575b600080fd5b603e60383660046052565b50600190565b604051901515815260200160405180910390f35b600060208284031215606357600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114608657600080fd5b939250505056fea164736f6c6343000811000a")}}]}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would actually suggest a slightly different mock::node::setup API that is similar to the mock::http::setup with the exception that it is agnostic to the JSON RPC stuff (so changes to the Web3 library with how it chooses IDs do not affect the test).

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not entirely sure what this mean, but maybe mocking specifically the from/to/calldata fields would allow some form of verification without having to make sense of the full tx encoding? But I think the proposed solution is also fine.

crates/solvers/src/tests/dex/partial_fill.rs Show resolved Hide resolved
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.

👏

crates/contracts/solidity/Swapper.sol Show resolved Hide resolved
crates/contracts/solidity/Swapper.sol Show resolved Hide resolved
@@ -71,7 +79,29 @@ pub async fn load<T: DeserializeOwned>(path: &Path) -> (super::Config, T) {

let dex: T = unwrap_or_log(config.dex.try_into(), &path);

// Take advantage of the fact that deterministic deployment means that all
// CoW Protocol contracts have the same address.
let contracts = contracts::Contracts::for_chain(eth::ChainId::Mainnet);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is quite hacky. Given that we already instantiate an rpc three lines below and the method is already async, can't we just get the chain id from the rpc?

Copy link
Contributor

Choose a reason for hiding this comment

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

Implementing this is trivial for the regular case but making it fit nicely with tests is not simple so I reverted it again.
Since this feature is pretty important I will merge the PR without this suggestion and keep thinking about better solutions in the mean time.

crates/solvers/src/infra/config/dex/mod.rs Show resolved Hide resolved
crates/solvers/src/infra/dex/simulator.rs Show resolved Hide resolved
@@ -94,7 +94,30 @@ async fn tested_amounts_adjust_depending_on_response() {
])
.await;

let engine = tests::SolverEngine::new("balancer", balancer::config(&api.address)).await;
let simulation_node = mock::http::setup(vec![mock::http::Expectation::Post {
path: mock::http::Path::Any,
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not entirely sure what this mean, but maybe mocking specifically the from/to/calldata fields would allow some form of verification without having to make sense of the full tx encoding? But I think the proposed solution is also fine.

@github-actions
Copy link

github-actions bot commented Oct 17, 2023

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@MartinquaXD
Copy link
Contributor

cc @nlordell since the CLA bot failed to tag you correctly for your contribution agreement. ☝️

@nlordell
Copy link
Contributor Author

@MartinquaXD - it looks like it's because I unlinked my [email protected] email from my GH account (sorry, didn't know it would have any ramifications :/). Since I don't have email access anymore, I don't think I can do it.

I would recommend just rebasing and removing me as an author from the commit (I don't mind at all), something like:

git rebase -r main..simulate-trades-in-solvers \
    --exec 'git commit --amend --no-edit --reset-author'

@nlordell
Copy link
Contributor Author

FWIW, in case there are some legal issues further down the line:

I have read the CLA Document and I hereby re-sign the CLA (I have already signed it in the past).

@MartinquaXD MartinquaXD force-pushed the simulate-trades-in-solvers branch from 0faba92 to f4a4b88 Compare October 18, 2023 09:28
@MartinquaXD MartinquaXD enabled auto-merge (squash) October 18, 2023 09:54
@MartinquaXD MartinquaXD disabled auto-merge October 18, 2023 09:54
@MartinquaXD MartinquaXD enabled auto-merge (squash) October 18, 2023 11:28
@MartinquaXD MartinquaXD merged commit 7aeb32b into main Oct 18, 2023
7 checks passed
@MartinquaXD MartinquaXD deleted the simulate-trades-in-solvers branch October 18, 2023 11:29
@github-actions github-actions bot locked and limited conversation to collaborators Oct 18, 2023
Copy link
Contributor

@sunce86 sunce86 left a comment

Choose a reason for hiding this comment

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

LG, just a comment around using gas estimates

// We are fine with just using heuristic gas for market orders,
// since it doesn't really play a role in the final solution.
self.gas
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry I did not review the PR before merging.

Is it possible to move out gas estimation at the callsite so we can use the accurate gas estimate for success_probability calculation also?

let Some(solution) = swap
.into_solution(order.clone(), gas_price, sell, score, &self.simulator)
.await
else {
tracing::debug!("no solution for swap");
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here, would like to use simulated gas estimate for success_probability calculation.

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.

bug: The Staging 0x solver does not compute a fee for fok limit orders
4 participants