Skip to content

Commit

Permalink
Add gnosis chain e2e forked test (#2311)
Browse files Browse the repository at this point in the history
# Description
Added a Gnosis Chain e2e forked test. We have e2e Gnosis Chain tests at
Enso and this small upstream change will help remove a lot of our
boilerplate and would help other solvers run Gnosis Chain e2e tests.

# Changes
- `FORK_URL` has been replaced by `FORK_URL_MAINNET` and
`FORK_URL_GNOSIS`, which should be updated in GitHub secrets.
- Added HoneySwap addresses under UniswapV2 contracts in
`crates/contracts/build.rs` as they have the same ABI and can then use
the same `Contracts` struct across Mainnet and Gnosis Chain tests.
- A `default_pool_code` function that returns the pool code for the
`Contracts` struct depending on the new `chain_id` value.
 - A limit order test that runs against Gnosis Chain.
 
## How to test
The `test-forked-node` CI job will test this. Locally I ran
`FORK_URL_MAINNET="<secret>" FORK_URL_GNOSIS="<secret>" cargo nextest
run --no-capture -p e2e forked_node --run-ignored ignored-only` and both
fork tests passed.
  • Loading branch information
devanoneth authored Jan 23, 2024
1 parent 986a1a3 commit 09c681f
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 17 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ jobs:
CARGO_PROFILE_DEV_DEBUG: 0
CARGO_PROFILE_TEST_DEBUG: 0
CARGO_TERM_COLOR: always
FORK_URL: ${{ secrets.FORK_URL }}
FORK_URL_MAINNET: ${{ secrets.FORK_URL_MAINNET }}
FORK_URL_GNOSIS: ${{ secrets.FORK_URL_GNOSIS }}
TOML_TRACE_ERROR: 1
steps:
- uses: actions/checkout@v3
Expand Down
6 changes: 4 additions & 2 deletions crates/contracts/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,14 +586,16 @@ fn main() {
builder
.add_network_str(MAINNET, "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f")
.add_network_str(GOERLI, "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f")
// Not available on Sepolia or Gnosis Chain
.add_network_str(GNOSIS, "0xA818b4F111Ccac7AA31D0BCc0806d64F2E0737D7")
// Not available on Sepolia
});
generate_contract_with_config("UniswapV2Router02", |builder| {
// <https://docs.uniswap.org/contracts/v2/reference/smart-contracts/router-02>
builder
.add_network_str(MAINNET, "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D")
.add_network_str(GOERLI, "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D")
// Not available on Sepolia or Gnosis Chain
.add_network_str(GNOSIS, "0x1C232F01118CB8B424793ae03F870aa7D0ac7f77")
// Not available on Sepolia
});
generate_contract_with_config("UniswapV3SwapRouter", |builder| {
// <https://github.com/Uniswap/v3-periphery/blob/697c2474757ea89fec12a4e6db16a574fe259610/deploys.md>
Expand Down
5 changes: 2 additions & 3 deletions crates/e2e/src/setup/colocation.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use {
crate::{nodes::NODE_HOST, setup::*},
ethcontract::{H160, H256, U256},
ethcontract::{H160, U256},
reqwest::Url,
shared::sources::uniswap_v2::UNISWAP_INIT,
tokio::task::JoinHandle,
};

Expand Down Expand Up @@ -112,7 +111,7 @@ mempool = "public"
contracts.gp_settlement.address(),
contracts.weth.address(),
contracts.uniswap_v2_router.address(),
H256(UNISWAP_INIT),
contracts.default_pool_code(),
));
let args = vec![
"driver".to_string(),
Expand Down
16 changes: 15 additions & 1 deletion crates/e2e/src/setup/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ use {
UniswapV2Router02,
WETH9,
},
ethcontract::{Address, U256},
ethcontract::{Address, H256, U256},
model::DomainSeparator,
shared::ethrpc::Web3,
};

pub struct Contracts {
pub chain_id: u64,
pub balancer_vault: BalancerV2Vault,
pub gp_settlement: GPv2Settlement,
pub gp_authenticator: GPv2AllowListAuthentication,
Expand All @@ -36,6 +37,9 @@ impl Contracts {
let gp_settlement = GPv2Settlement::deployed(web3).await.unwrap();

Self {
chain_id: network_id
.parse()
.expect("Couldn't parse network ID to u64"),
balancer_vault: BalancerV2Vault::deployed(web3).await.unwrap(),
gp_authenticator: GPv2AllowListAuthentication::deployed(web3).await.unwrap(),
uniswap_v2_factory: UniswapV2Factory::deployed(web3).await.unwrap(),
Expand Down Expand Up @@ -138,6 +142,9 @@ impl Contracts {
let hooks = deploy!(HooksTrampoline(gp_settlement.address()));

Self {
chain_id: network_id
.parse()
.expect("Couldn't parse network ID to u64"),
balancer_vault,
gp_settlement,
gp_authenticator,
Expand All @@ -150,4 +157,11 @@ impl Contracts {
hooks,
}
}

pub fn default_pool_code(&self) -> H256 {
match self.chain_id {
100 => H256(shared::sources::uniswap_v2::HONEYSWAP_INIT),
_ => H256(shared::sources::uniswap_v2::UNISWAP_INIT),
}
}
}
2 changes: 1 addition & 1 deletion crates/e2e/src/setup/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl<'a> Services<'a> {
format!(
"--custom-univ2-baseline-sources={:?}|{:?}",
self.contracts.uniswap_v2_router.address(),
H256(shared::sources::uniswap_v2::UNISWAP_INIT),
self.contracts.default_pool_code(),
),
format!(
"--settlement-contract-address={:?}",
Expand Down
135 changes: 126 additions & 9 deletions crates/e2e/tests/e2e/limit_orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,37 @@ async fn local_node_mixed_limit_and_market_orders() {
}

/// The block number from which we will fetch state for the forked tests.
pub const FORK_BLOCK: u64 = 18477910;
/// USDC whale address as per [FORK_BLOCK].
pub const USDC_WHALE: H160 = H160(hex_literal::hex!(
const FORK_BLOCK_MAINNET: u64 = 18477910;
/// USDC whale address as per [FORK_BLOCK_MAINNET].
const USDC_WHALE_MAINNET: H160 = H160(hex_literal::hex!(
"28c6c06298d514db089934071355e5743bf21d60"
));

#[tokio::test]
#[ignore]
async fn forked_node_single_limit_order_mainnet() {
async fn forked_node_mainnet_single_limit_order() {
run_forked_test_with_block_number(
forked_single_limit_order_test,
std::env::var("FORK_URL").expect("FORK_URL must be set to run forked tests"),
FORK_BLOCK,
forked_mainnet_single_limit_order_test,
std::env::var("FORK_URL_MAINNET")
.expect("FORK_URL_MAINNET must be set to run forked tests"),
FORK_BLOCK_MAINNET,
)
.await;
}

const FORK_BLOCK_GNOSIS: u64 = 32070725;
/// USDC whale address as per [FORK_BLOCK_GNOSIS].
const USDC_WHALE_GNOSIS: H160 = H160(hex_literal::hex!(
"ba12222222228d8ba445958a75a0704d566bf2c8"
));

#[tokio::test]
#[ignore]
async fn forked_node_gnosis_single_limit_order() {
run_forked_test_with_block_number(
forked_gnosis_single_limit_order_test,
std::env::var("FORK_URL_GNOSIS").expect("FORK_URL_GNOSIS must be set to run forked tests"),
FORK_BLOCK_GNOSIS,
)
.await;
}
Expand Down Expand Up @@ -455,7 +473,7 @@ async fn too_many_limit_orders_test(web3: Web3) {
assert!(body.contains("TooManyLimitOrders"));
}

async fn forked_single_limit_order_test(web3: Web3) {
async fn forked_mainnet_single_limit_order_test(web3: Web3) {
let mut onchain = OnchainComponents::deployed(web3.clone()).await;
let forked_node_api = web3.api::<ForkedNodeApi<_>>();

Expand All @@ -478,7 +496,10 @@ async fn forked_single_limit_order_test(web3: Web3) {
);

// Give trader some USDC
let usdc_whale = forked_node_api.impersonate(&USDC_WHALE).await.unwrap();
let usdc_whale = forked_node_api
.impersonate(&USDC_WHALE_MAINNET)
.await
.unwrap();
tx!(
usdc_whale,
token_usdc.transfer(trader.address(), to_wei_with_exp(1000, 6))
Expand Down Expand Up @@ -547,3 +568,99 @@ async fn forked_single_limit_order_test(web3: Web3) {
assert!(sell_token_balance_before > sell_token_balance_after);
assert!(buy_token_balance_after >= buy_token_balance_before + to_wei_with_exp(500, 6));
}

async fn forked_gnosis_single_limit_order_test(web3: Web3) {
let mut onchain = OnchainComponents::deployed(web3.clone()).await;
let forked_node_api = web3.api::<ForkedNodeApi<_>>();

let [solver] = onchain.make_solvers_forked(to_wei(1)).await;

let [trader] = onchain.make_accounts(to_wei(1)).await;

let token_usdc = ERC20::at(
&web3,
"0xddafbb505ad214d7b80b1f830fccc89b60fb7a83"
.parse()
.unwrap(),
);

let token_wxdai = ERC20::at(
&web3,
"0xe91d153e0b41518a2ce8dd3d7944fa863463a97d"
.parse()
.unwrap(),
);

// Give trader some USDC
let usdc_whale = forked_node_api
.impersonate(&USDC_WHALE_GNOSIS)
.await
.unwrap();
tx!(
usdc_whale,
token_usdc.transfer(trader.address(), to_wei_with_exp(1000, 6))
);

// Approve GPv2 for trading
tx!(
trader.account(),
token_usdc.approve(onchain.contracts().allowance, to_wei_with_exp(1000, 6))
);

// Place Orders
let services = Services::new(onchain.contracts()).await;
services.start_protocol(solver).await;

let order = OrderCreation {
sell_token: token_usdc.address(),
sell_amount: to_wei_with_exp(1000, 6),
buy_token: token_wxdai.address(),
buy_amount: to_wei(500),
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.private_key()).unwrap()),
);
let order_id = services.create_order(&order).await.unwrap();
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.address())
.call()
.await
.unwrap();
let buy_token_balance_before = token_wxdai
.balance_of(trader.address())
.call()
.await
.unwrap();

wait_for_condition(TIMEOUT, || async { services.solvable_orders().await == 1 })
.await
.unwrap();

wait_for_condition(TIMEOUT, || async { services.solvable_orders().await == 0 })
.await
.unwrap();

let sell_token_balance_after = token_usdc
.balance_of(trader.address())
.call()
.await
.unwrap();
let buy_token_balance_after = token_wxdai
.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(500));
}

0 comments on commit 09c681f

Please sign in to comment.