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

Baseline solver limit orders support #2326

Merged
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2e18b36
Baseline LimitOrder support
squadgazzz Jan 24, 2024
4b42119
Precision fix
squadgazzz Jan 24, 2024
c3d45a2
Bfp -> U256
squadgazzz Jan 25, 2024
2a2a8aa
Refactoring
squadgazzz Jan 25, 2024
cffd9c0
More tests
squadgazzz Jan 25, 2024
381416d
Naming
squadgazzz Jan 25, 2024
0eb67d2
Redundant function
squadgazzz Jan 25, 2024
dce04b6
Adjusted value
squadgazzz Jan 25, 2024
a830885
Clean-up
squadgazzz Jan 25, 2024
621ca08
Align calculations with 0x smart contract
squadgazzz Jan 26, 2024
ec9887d
Naming
squadgazzz Jan 26, 2024
67dba54
Adjust formula
squadgazzz Jan 26, 2024
c86ae17
Minor test fixes
squadgazzz Feb 1, 2024
b8cfde1
Domain separator fix
squadgazzz Feb 1, 2024
bea923c
Fixed hash structure
squadgazzz Feb 2, 2024
f848362
Whitelist solvers and fix values
squadgazzz Feb 21, 2024
fca90f4
Merge branch 'e2e/0x-liquidity-fetching' into baseline-solver-limit-o…
squadgazzz Feb 21, 2024
9ad39cd
Redundant log
squadgazzz Feb 21, 2024
a3167b1
Fork url env name
squadgazzz Feb 21, 2024
3a6b13e
Config fix
squadgazzz Feb 21, 2024
de418ea
Merge branch 'e2e/0x-liquidity-fetching' into baseline-solver-limit-o…
squadgazzz Apr 1, 2024
e818b6d
Missing app_data field
squadgazzz Apr 1, 2024
49df1fb
Merge branch 'e2e/0x-liquidity-fetching' into baseline-solver-limit-o…
squadgazzz Apr 1, 2024
f10fed0
Redundant import
squadgazzz Apr 1, 2024
6bcfbac
Private field
squadgazzz Apr 1, 2024
c27296d
Fix after merge
squadgazzz Apr 1, 2024
fd7880f
Native 0x liquidity orders
squadgazzz Apr 2, 2024
68e7da3
Comments
squadgazzz Apr 2, 2024
4de0d47
Redundant mock
squadgazzz Apr 2, 2024
7e061d8
Review fixes
squadgazzz Apr 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions crates/e2e/src/nodes/forked_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,16 @@ impl<T: Transport> ForkedNodeApi<T> {
.execute("anvil_setBalance", vec![json_address, json_balance]),
)
}

// Makes GPv2 auth contract always return `true` to make any solver to be
// whitelisted.
pub fn set_mocked_settle(&self) -> CallFuture<(), T::Out> {
let gpv2_auth_address_json =
serde_json::json!("0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE");
let bytecode_json = serde_json::json!("0x600160005260206000F3");
CallFuture::new(
self.transport
.execute("anvil_setCode", vec![gpv2_auth_address_json, bytecode_json]),
)
}
}
103 changes: 46 additions & 57 deletions crates/e2e/tests/e2e/liquidity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ async fn zero_ex_liquidity(web3: Web3) {
let forked_node_api = web3.api::<ForkedNodeApi<_>>();

let [solver] = onchain.make_solvers_forked(to_wei(1)).await;
let [trader_a, trader_b, zeroex_maker, zeroex_taker] = onchain.make_accounts(to_wei(1)).await;
let [trader, zeroex_maker] = onchain.make_accounts(to_wei(1)).await;
forked_node_api.set_mocked_settle().await.unwrap();

let token_usdc = ERC20::at(
&web3,
Expand All @@ -78,65 +79,54 @@ async fn zero_ex_liquidity(web3: Web3) {
.unwrap(),
);

let zeroex = IZeroEx::deployed(&web3).await.unwrap();

let amount = 500;

// Give trader some USDC
let usdc_whale = forked_node_api
.impersonate(&crate::limit_orders::USDC_WHALE)
.await
.unwrap();
tx!(
usdc_whale,
token_usdc.transfer(trader_a.address(), to_wei_with_exp(500, 6))
token_usdc.transfer(trader.address(), to_wei_with_exp(amount, 6))
);

// Give trader some USDT
let usdt_whale = forked_node_api.impersonate(&USDT_WHALE).await.unwrap();
tx!(
usdt_whale,
token_usdt.transfer(trader_b.address(), to_wei_with_exp(500, 6))
token_usdt.transfer(zeroex_maker.address(), to_wei_with_exp(amount * 3, 6))
);

// Approve GPv2 for trading
tx!(
trader_a.account(),
token_usdc.approve(onchain.contracts().allowance, to_wei_with_exp(500, 6))
trader.account(),
token_usdc.approve(onchain.contracts().allowance, to_wei_with_exp(amount, 6))
);
tx!(
trader_b.account(),
token_usdt.approve(onchain.contracts().allowance, to_wei_with_exp(500, 6))
zeroex_maker.account(),
token_usdt.approve(zeroex.address(), to_wei_with_exp(amount * 3, 6))
);

let order_a = OrderCreation {
let order = OrderCreation {
sell_token: token_usdc.address(),
sell_amount: to_wei_with_exp(500, 6),
sell_amount: to_wei_with_exp(amount, 6),
buy_token: token_usdt.address(),
buy_amount: to_wei_with_exp(500, 6),
valid_to: model::time::now_in_epoch_seconds() + 300,
kind: OrderKind::Sell,
..Default::default()
}
.sign(
EcdsaSigningScheme::Eip712,
&onchain.contracts().domain_separator,
SecretKeyRef::from(&SecretKey::from_slice(trader_a.private_key()).unwrap()),
);
let order_b = OrderCreation {
sell_token: token_usdt.address(),
sell_amount: to_wei_with_exp(500, 6),
buy_token: token_usdc.address(),
buy_amount: to_wei_with_exp(500, 6),
buy_amount: to_wei_with_exp(amount, 6),
valid_to: model::time::now_in_epoch_seconds() + 300,
kind: OrderKind::Sell,
..Default::default()
}
.sign(
EcdsaSigningScheme::Eip712,
&onchain.contracts().domain_separator,
SecretKeyRef::from(&SecretKey::from_slice(trader_b.private_key()).unwrap()),
SecretKeyRef::from(&SecretKey::from_slice(trader.private_key()).unwrap()),
);

let zeroex = IZeroEx::deployed(&web3).await.unwrap();
let zeroex_api_port = {
let order = order_a.clone();
let order = order.clone();
let chain_id = web3.eth().chain_id().await.unwrap().as_u64();
let gpv2_addr = onchain.contracts().gp_settlement.address();
let zeroex_addr = zeroex.address();
Expand All @@ -145,7 +135,6 @@ async fn zero_ex_liquidity(web3: Web3) {
query,
order.clone(),
zeroex_maker.clone(),
zeroex_taker.clone(),
zeroex_addr,
gpv2_addr,
chain_id,
Expand All @@ -161,7 +150,8 @@ async fn zero_ex_liquidity(web3: Web3) {

// Place Orders
let services = Services::new(onchain.contracts()).await;
let solver_endpoint = colocation::start_naive_solver().await;
let solver_endpoint =
colocation::start_baseline_solver(onchain.contracts().weth.address()).await;
colocation::start_driver_with_zeroex_liquidity(
onchain.contracts(),
vec![SolverEngine {
Expand All @@ -179,20 +169,20 @@ async fn zero_ex_liquidity(web3: Web3) {
"--price-estimation-drivers=test_solver|http://localhost:11088/test_solver".to_string(),
])
.await;
let order_id = services.create_order(&order_a).await.unwrap();
services.create_order(&order_b).await.unwrap();
let order_id = services.create_order(&order).await.unwrap();
println!("newlog order_id={:?}", order_id);
let limit_order = services.get_order(&order_id).await.unwrap();
assert_eq!(limit_order.metadata.class, OrderClass::Limit);

// Drive solution
tracing::info!("Waiting for trade.");
let sell_token_balance_before = token_usdc
.balance_of(trader_a.address())
.balance_of(trader.address())
.call()
.await
.unwrap();
let buy_token_balance_before = token_usdt
.balance_of(trader_a.address())
.balance_of(trader.address())
.call()
.await
.unwrap();
Expand All @@ -206,47 +196,46 @@ async fn zero_ex_liquidity(web3: Web3) {
.unwrap();

let sell_token_balance_after = token_usdc
.balance_of(trader_a.address())
.balance_of(trader.address())
.call()
.await
.unwrap();
let buy_token_balance_after = token_usdt
.balance_of(trader_a.address())
.balance_of(trader.address())
.call()
.await
.unwrap();

assert!(sell_token_balance_before > sell_token_balance_after);
assert!(buy_token_balance_after >= buy_token_balance_before + to_wei_with_exp(500, 6));
assert!(buy_token_balance_after >= buy_token_balance_before + to_wei_with_exp(amount, 6));
}

fn orders_query_handler(
query: &OrdersQuery,
order_creation: OrderCreation,
zeroex_maker: TestAccount,
zeroex_taker: TestAccount,
zeroex_addr: H160,
gpv2_addr: H160,
chain_id: u64,
) -> Result<Vec<OrderRecord>, ZeroExResponseError> {
if query.sender == Some(gpv2_addr) {
let typed_order = Eip712TypedZeroExOrder {
maker_token: order_creation.sell_token,
taker_token: order_creation.buy_token,
maker_amount: order_creation.sell_amount.as_u128() * 2,
taker_amount: order_creation.buy_amount.as_u128() * 2,
maker_token: order_creation.buy_token,
taker_token: order_creation.sell_token,
maker_amount: order_creation.buy_amount.as_u128() * 3,
taker_amount: order_creation.sell_amount.as_u128() * 2,
Comment on lines +226 to +227
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This multiplication is required to pass this check. Not sure it is 100% valid.

Copy link
Contributor

@fleupold fleupold Feb 22, 2024

Choose a reason for hiding this comment

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

🤔 to me it seems that the inequality in the check should be a <= instead of <.

Never mind. Is it possible that the fee amount needs to be taken care of here? How big is the discrepancy exactly?

Why even multiply with 2 (maybe add a comment)?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe instead of adjusting the amount with these factors it's a better idea to make the order partially fillable. That way we don't have to have a comment for all the factors but only when we assert that the traded amounts look good in the end.

taker_token_fee_amount: 0,
maker: zeroex_maker.address(),
taker: zeroex_taker.address(),
sender: zeroex_maker.address(),
taker: gpv2_addr,
sender: gpv2_addr,
fee_recipient: zeroex_addr,
pool: H256::default(),
expiry: NaiveDateTime::MAX.timestamp() as u64,
salt: U256::from(Utc::now().timestamp()),
};
Ok(vec![typed_order.to_order_record(
chain_id,
gpv2_addr,
zeroex_addr,
zeroex_maker,
)])
} else if query.sender
Expand Down Expand Up @@ -337,17 +326,17 @@ impl Eip712TypedZeroExOrder {
fn hash_struct(&self) -> [u8; 32] {
let mut hash_data = [0u8; 416];
hash_data[0..32].copy_from_slice(&Self::ZEROEX_LIMIT_ORDER_TYPEHASH);
hash_data[32..52].copy_from_slice(self.maker_token.as_fixed_bytes());
hash_data[64..84].copy_from_slice(self.taker_token.as_fixed_bytes());
hash_data[96..112].copy_from_slice(&self.maker_amount.to_be_bytes());
hash_data[128..144].copy_from_slice(&self.taker_amount.to_be_bytes());
hash_data[160..176].copy_from_slice(&self.taker_token_fee_amount.to_be_bytes());
hash_data[192..212].copy_from_slice(self.maker.as_fixed_bytes());
hash_data[224..244].copy_from_slice(self.taker.as_fixed_bytes());
hash_data[256..276].copy_from_slice(self.sender.as_fixed_bytes());
hash_data[288..308].copy_from_slice(self.fee_recipient.as_fixed_bytes());
hash_data[44..64].copy_from_slice(self.maker_token.as_fixed_bytes());
hash_data[76..96].copy_from_slice(self.taker_token.as_fixed_bytes());
hash_data[112..128].copy_from_slice(&self.maker_amount.to_be_bytes());
hash_data[144..160].copy_from_slice(&self.taker_amount.to_be_bytes());
hash_data[176..192].copy_from_slice(&self.taker_token_fee_amount.to_be_bytes());
hash_data[204..224].copy_from_slice(self.maker.as_fixed_bytes());
hash_data[236..256].copy_from_slice(self.taker.as_fixed_bytes());
hash_data[268..288].copy_from_slice(self.sender.as_fixed_bytes());
hash_data[300..320].copy_from_slice(self.fee_recipient.as_fixed_bytes());
hash_data[320..352].copy_from_slice(self.pool.as_fixed_bytes());
hash_data[352..360].copy_from_slice(&self.expiry.to_be_bytes());
hash_data[376..384].copy_from_slice(&self.expiry.to_be_bytes());
self.salt.to_big_endian(&mut hash_data[384..416]);
signing::keccak256(&hash_data)
}
Expand All @@ -371,9 +360,9 @@ impl ZeroExDomainSeparator {
);
}
let abi_encode_string = encode(&[
Token::Uint((*DOMAIN_TYPE_HASH).into()),
Token::Uint((*DOMAIN_NAME).into()),
Token::Uint((*DOMAIN_VERSION).into()),
Token::FixedBytes((*DOMAIN_TYPE_HASH).into()),
Token::FixedBytes((*DOMAIN_NAME).into()),
Token::FixedBytes((*DOMAIN_VERSION).into()),
Token::Uint(chain_id.into()),
Token::Address(contract_addr),
]);
Expand Down
2 changes: 2 additions & 0 deletions crates/solvers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@ tracing = { workspace = true }
[dev-dependencies]
glob = "0.3"
tempfile = "3"
hex-literal = { workspace = true }
ethcontract = { workspace = true }
Loading
Loading