Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit ab487f4
Author: MartinquaXD <[email protected]>
Date:   Sat Jun 1 08:44:04 2024 +0200

    Fix clippy warning

commit 576cf19
Author: MartinquaXD <[email protected]>
Date:   Sat Jun 1 08:39:19 2024 +0200

    Implemented suggested changes

commit 60650da
Author: Mateo <[email protected]>
Date:   Fri May 31 18:22:47 2024 +0200

    Remove log from the mock solver

commit 859380a
Author: Mateo <[email protected]>
Date:   Fri May 31 15:37:34 2024 +0200

    Linter

commit 4a67faf
Author: Mateo <[email protected]>
Date:   Fri May 31 15:22:14 2024 +0200

    Implement e2e tests for JIT orders

commit debfa39
Author: Dusan Stanivukovic <[email protected]>
Date:   Fri May 31 09:37:51 2024 +0200

    Circuit breaker remove solver (#2705)

    # Description
    Related to #2667

    POC implementation for using "Roles" safe module to grant special role
    to an EOA to sign and execute "removeSolver" function on behalf of the
    gpv2_authenticator manager/owner safe.

    Need to add tests to see if this actually works.

    # Changes
    <!-- List of detailed changes (how the change is accomplished) -->

    - [ ] Added `Roles` smart contract
    - [ ] Added EOA account as configuration
    - [ ] Implemented `remove_solver` function

    ## How to test
    todo

    ---------

    Co-authored-by: Mateo <[email protected]>
    Co-authored-by: Mateo-mro <[email protected]>
  • Loading branch information
MartinquaXD committed Jun 1, 2024
1 parent 6c0e8ff commit bbebb5e
Show file tree
Hide file tree
Showing 15 changed files with 591 additions and 32 deletions.
9 changes: 9 additions & 0 deletions Cargo.lock

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

87 changes: 87 additions & 0 deletions crates/autopilot/src/infra/blockchain/authenticator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use {
crate::{
domain::{self, eth},
infra::blockchain::{
contracts::{deployment_address, Contracts},
ChainId,
},
},
ethcontract::{dyns::DynWeb3, GasPrice},
};

#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Manager {
/// The authenticator contract that decides which solver is allowed to
/// submit settlements.
authenticator: contracts::GPv2AllowListAuthentication,
/// The safe module that is used to provide special role to EOA.
authenticator_role: contracts::Roles,
/// The EOA that is allowed to remove solvers.
authenticator_eoa: ethcontract::Account,
}

impl Manager {
/// Creates an authenticator which can remove solvers from the allow-list
pub async fn new(
web3: DynWeb3,
chain: ChainId,
contracts: Contracts,
authenticator_pk: eth::H256,
) -> Self {
let authenticator_role = contracts::Roles::at(
&web3,
deployment_address(contracts::Roles::raw_contract(), &chain).expect("roles address"),
);

Self {
authenticator: contracts.authenticator().clone(),
authenticator_role,
authenticator_eoa: ethcontract::Account::Offline(
ethcontract::PrivateKey::from_raw(authenticator_pk.0).unwrap(),
None,
),
}
}

/// Fire and forget: Removes solver from the allow-list in the authenticator
/// contract. This solver will no longer be able to settle.
#[allow(dead_code)]
fn remove_solver(&self, solver: domain::eth::Address) {
let calldata = self
.authenticator
.methods()
.remove_solver(solver.into())
.tx
.data
.expect("missing calldata");
let authenticator_eoa = self.authenticator_eoa.clone();
let authenticator_address = self.authenticator.address();
let authenticator_role = self.authenticator_role.clone();
tokio::task::spawn(async move {
// This value comes from the TX posted in the issue: https://github.com/cowprotocol/services/issues/2667
let mut byte_array = [0u8; 32];
byte_array[31] = 1;
authenticator_role
.methods()
.exec_transaction_with_role(
authenticator_address,
0.into(),
ethcontract::Bytes(calldata.0),
0,
ethcontract::Bytes(byte_array),
true,
)
.from(authenticator_eoa)
.gas_price(GasPrice::Eip1559 {
// These are arbitrary high numbers that should be enough for a tx to be settled
// anytime.
max_fee_per_gas: 1000.into(),
max_priority_fee_per_gas: 5.into(),
})
.send()
.await
.inspect_err(|err| tracing::error!(?solver, ?err, "failed to remove the solver"))
});
}
}
6 changes: 4 additions & 2 deletions crates/autopilot/src/infra/blockchain/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ pub struct Contracts {
settlement: contracts::GPv2Settlement,
weth: contracts::WETH9,
chainalysis_oracle: Option<contracts::ChainalysisOracle>,
authenticator: contracts::GPv2AllowListAuthentication,

/// The authenticator contract that decides which solver is allowed to
/// submit settlements.
authenticator: contracts::GPv2AllowListAuthentication,
/// The domain separator for settlement contract used for signing orders.
settlement_domain_separator: domain::eth::DomainSeparator,
}

#[derive(Debug, Default, Clone, Copy)]
#[derive(Debug, Clone)]
pub struct Addresses {
pub settlement: Option<H160>,
pub weth: Option<H160>,
Expand Down
15 changes: 13 additions & 2 deletions crates/autopilot/src/infra/blockchain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use {
url::Url,
};

pub mod authenticator;
pub mod contracts;

/// Chain ID as defined by EIP-155.
Expand Down Expand Up @@ -62,6 +63,11 @@ impl Rpc {
pub fn web3(&self) -> &DynWeb3 {
&self.web3
}

/// Returns a reference to the underlying RPC URL.
pub fn url(&self) -> &Url {
&self.url
}
}

/// The Ethereum blockchain.
Expand All @@ -80,8 +86,13 @@ impl Ethereum {
///
/// Since this type is essential for the program this method will panic on
/// any initialization error.
pub async fn new(rpc: Rpc, addresses: contracts::Addresses, poll_interval: Duration) -> Self {
let Rpc { web3, chain, url } = rpc;
pub async fn new(
web3: DynWeb3,
chain: ChainId,
url: Url,
addresses: contracts::Addresses,
poll_interval: Duration,
) -> Self {
let contracts = Contracts::new(&web3, &chain, addresses).await;

Self {
Expand Down
19 changes: 13 additions & 6 deletions crates/autopilot/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ use {
},
domain,
event_updater::EventUpdater,
infra::{self},
infra::{self, blockchain::ChainId},
run_loop::RunLoop,
shadow,
solvable_orders::SolvableOrdersCache,
},
clap::Parser,
contracts::{BalancerV2Vault, IUniswapV3Factory},
ethcontract::{errors::DeployError, BlockNumber},
ethcontract::{dyns::DynWeb3, errors::DeployError, BlockNumber},
ethrpc::current_block::block_number_to_block_number_hash,
futures::StreamExt,
model::DomainSeparator,
Expand Down Expand Up @@ -87,11 +87,13 @@ async fn ethrpc(url: &Url) -> infra::blockchain::Rpc {
}

async fn ethereum(
ethrpc: infra::blockchain::Rpc,
web3: DynWeb3,
chain: ChainId,
url: Url,
contracts: infra::blockchain::contracts::Addresses,
poll_interval: Duration,
) -> infra::Ethereum {
infra::Ethereum::new(ethrpc, contracts, poll_interval).await
infra::Ethereum::new(web3, chain, url, contracts, poll_interval).await
}

pub async fn start(args: impl Iterator<Item = String>) {
Expand Down Expand Up @@ -149,13 +151,18 @@ pub async fn run(args: Arguments) {
}

let ethrpc = ethrpc(&args.shared.node_url).await;
let chain = ethrpc.chain();
let web3 = ethrpc.web3().clone();
let url = ethrpc.url().clone();
let contracts = infra::blockchain::contracts::Addresses {
settlement: args.shared.settlement_contract_address,
weth: args.shared.native_token_address,
};
let eth = ethereum(
ethrpc,
contracts,
web3.clone(),
chain,
url,
contracts.clone(),
args.shared.current_block.block_stream_poll_interval,
)
.await;
Expand Down
1 change: 1 addition & 0 deletions crates/contracts/artifacts/Roles.json

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions crates/contracts/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,42 @@ fn main() {
});
generate_contract("GnosisSafeProxy");
generate_contract("GnosisSafeProxyFactory");
generate_contract_with_config("Roles", |builder| {
builder
.contract_mod_override("roles")
.add_network(
MAINNET,
Network {
address: addr("0x9646fDAD06d3e24444381f44362a3B0eB343D337"),
// <https://etherscan.io/tx/0x351ecf2966f8cdd54e1de1d4cb326217fa89f6064231dfc1fe56417b9b48e942>
deployment_information: Some(DeploymentInformation::BlockNumber(18692162)),
},
)
.add_network(
GNOSIS,
Network {
address: addr("0x9646fDAD06d3e24444381f44362a3B0eB343D337"),
// <https://gnosisscan.io/tx/0x4b1ec57c4048afd40904ea9b91dad38ec18d69ea0db965d624ffdd4abd284c96>
deployment_information: Some(DeploymentInformation::BlockNumber(31222929)),
},
)
.add_network(
SEPOLIA,
Network {
address: addr("0x9646fDAD06d3e24444381f44362a3B0eB343D337"),
// <https://sepolia.etherscan.io/tx/0x516f0f6b8ac669cb5ca3962833e520274169c1463da354be9faa2cb0e6afa8a6>
deployment_information: Some(DeploymentInformation::BlockNumber(4884885)),
},
)
.add_network(
ARBITRUM_ONE,
Network {
address: addr("0x9646fDAD06d3e24444381f44362a3B0eB343D337"),
// <https://arbiscan.io/tx/0x3860d6091e1baf8a9ba16e58ec437ec3644db2f4c0d9e2ba7fe37cfa0a4fa748>
deployment_information: Some(DeploymentInformation::BlockNumber(176504820)),
},
)
});
generate_contract_with_config("HoneyswapRouter", |builder| {
builder.add_network_str(GNOSIS, "0x1C232F01118CB8B424793ae03F870aa7D0ac7f77")
});
Expand Down
1 change: 1 addition & 0 deletions crates/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ include_contracts! {
GnosisSafeCompatibilityFallbackHandler;
GnosisSafeProxy;
GnosisSafeProxyFactory;
Roles;
HoneyswapRouter;
HooksTrampoline;
ISwaprPair;
Expand Down
6 changes: 6 additions & 0 deletions crates/e2e/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ app-data = { path = "../app-data" }
anyhow = { workspace = true }
async-trait = { workspace = true }
autopilot = { path = "../autopilot" }
axum = { workspace = true }
chrono = { workspace = true }
clap = { workspace = true }
contracts = { path = "../contracts" }
Expand All @@ -25,16 +26,21 @@ observe = { path = "../observe" }
orderbook = { path = "../orderbook" }
reqwest = { workspace = true, features = ["blocking"] }
secp256k1 = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
shared = { path = "../shared" }
solver = { path = "../solver" }
solvers = { path = "../solvers" }
solvers-dto = { path = "../solvers-dto" }
sqlx = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["macros", "process"] }
tower = "0.4"
tower-http = { version = "0.4", features = ["limit", "trace"] }
tracing = { workspace = true }
warp = { workspace = true }
web3 = { workspace = true, features = ["http"] }
uuid = { version = "1.4.1", features = ["v4"] }

[dev-dependencies]
app-data-hash = { path = "../app-data-hash" }
Expand Down
7 changes: 1 addition & 6 deletions crates/e2e/src/setup/colocation.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
use {
crate::{nodes::NODE_HOST, setup::*},
ethcontract::H160,
reqwest::Url,
tokio::task::JoinHandle,
};
use {crate::setup::*, ethcontract::H160, reqwest::Url, tokio::task::JoinHandle};

pub async fn start_baseline_solver(weth: H160) -> Url {
let config_file = config_tmp_file(format!(
Expand Down
3 changes: 2 additions & 1 deletion crates/e2e/src/setup/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod deploy;
#[macro_use]
pub mod onchain_components;
mod services;
mod solver;

use {
crate::nodes::{Node, NODE_HOST},
Expand All @@ -19,7 +20,7 @@ use {
},
tempfile::TempPath,
};
pub use {deploy::*, onchain_components::*, services::*};
pub use {deploy::*, onchain_components::*, services::*, solver::*};

/// Create a temporary file with the given content.
pub fn config_tmp_file<C: AsRef<[u8]>>(content: C) -> TempPath {
Expand Down
Loading

0 comments on commit bbebb5e

Please sign in to comment.